aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPieter Wuille <pieter@wuille.net>2023-09-11 13:54:32 -0400
committerfanquake <fanquake@gmail.com>2023-10-02 13:09:00 +0100
commit2c51a07c085b25246effa91a1f5f17dac560ff58 (patch)
tree97981377d50cd043417b54c09d21720446aeec15 /src
parent887cbfcc9376d79dcaabe13b58c33644df3a32b2 (diff)
Do not use std::vector = {} to release memory
Github-Pull: #28452 Rebased-From: 3fcd7fc7ff563bdc0e2bba66b4cbe72d898c876e
Diffstat (limited to 'src')
-rw-r--r--src/headerssync.cpp5
-rw-r--r--src/test/util_tests.cpp25
-rw-r--r--src/util/vector.h18
3 files changed, 46 insertions, 2 deletions
diff --git a/src/headerssync.cpp b/src/headerssync.cpp
index a3adfb4f70..f891063cd2 100644
--- a/src/headerssync.cpp
+++ b/src/headerssync.cpp
@@ -7,6 +7,7 @@
#include <pow.h>
#include <timedata.h>
#include <util/check.h>
+#include <util/vector.h>
// The two constants below are computed using the simulation script on
// https://gist.github.com/sipa/016ae445c132cdf65a2791534dfb7ae1
@@ -51,9 +52,9 @@ HeadersSyncState::HeadersSyncState(NodeId id, const Consensus::Params& consensus
void HeadersSyncState::Finalize()
{
Assume(m_download_state != State::FINAL);
- m_header_commitments = {};
+ ClearShrink(m_header_commitments);
m_last_header_received.SetNull();
- m_redownloaded_headers = {};
+ ClearShrink(m_redownloaded_headers);
m_redownload_buffer_last_hash.SetNull();
m_redownload_buffer_first_prev_hash.SetNull();
m_process_all_remaining_headers = false;
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 812737429d..c7358a78d1 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -1791,4 +1791,29 @@ BOOST_AUTO_TEST_CASE(util_WriteBinaryFile)
BOOST_CHECK(valid);
BOOST_CHECK_EQUAL(actual_text, expected_text);
}
+
+BOOST_AUTO_TEST_CASE(clearshrink_test)
+{
+ {
+ std::vector<uint8_t> v = {1, 2, 3};
+ ClearShrink(v);
+ BOOST_CHECK_EQUAL(v.size(), 0);
+ BOOST_CHECK_EQUAL(v.capacity(), 0);
+ }
+
+ {
+ std::vector<bool> v = {false, true, false, false, true, true};
+ ClearShrink(v);
+ BOOST_CHECK_EQUAL(v.size(), 0);
+ BOOST_CHECK_EQUAL(v.capacity(), 0);
+ }
+
+ {
+ std::deque<int> v = {1, 3, 3, 7};
+ ClearShrink(v);
+ BOOST_CHECK_EQUAL(v.size(), 0);
+ // std::deque has no capacity() we can observe.
+ }
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/util/vector.h b/src/util/vector.h
index 9b9218e54f..40ff73c293 100644
--- a/src/util/vector.h
+++ b/src/util/vector.h
@@ -49,4 +49,22 @@ inline V Cat(V v1, const V& v2)
return v1;
}
+/** Clear a vector (or std::deque) and release its allocated memory. */
+template<typename V>
+inline void ClearShrink(V& v) noexcept
+{
+ // There are various ways to clear a vector and release its memory:
+ //
+ // 1. V{}.swap(v)
+ // 2. v = V{}
+ // 3. v = {}; v.shrink_to_fit();
+ // 4. v.clear(); v.shrink_to_fit();
+ //
+ // (2) does not appear to release memory in glibc debug mode, even if v.shrink_to_fit()
+ // follows. (3) and (4) rely on std::vector::shrink_to_fit, which is only a non-binding
+ // request. Therefore, we use method (1).
+
+ V{}.swap(v);
+}
+
#endif // BITCOIN_UTIL_VECTOR_H