diff --git a/src/memusage.h b/src/memusage.h index 08be66172e3..9d9e549ef22 100644 --- a/src/memusage.h +++ b/src/memusage.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -84,10 +85,22 @@ struct stl_shared_counter size_t weak_count; }; -template -static inline size_t DynamicUsage(const std::vector& v) +template +static inline size_t DynamicUsage(const std::vector& v) { - return MallocUsage(v.capacity() * sizeof(X)); + return MallocUsage(v.capacity() * sizeof(T)); +} + +static inline size_t DynamicUsage(const std::string& s) +{ + const char* s_ptr = reinterpret_cast(&s); + // Don't count the dynamic memory used for string, if it resides in the + // "small string" optimization area (which stores data inside the object itself, up to some + // size; 15 bytes in modern libstdc++). + if (!std::less{}(s.data(), s_ptr) && !std::greater{}(s.data() + s.size(), s_ptr + sizeof(s))) { + return 0; + } + return MallocUsage(s.capacity()); } template diff --git a/src/net.cpp b/src/net.cpp index d76b39f75d5..f1ac681b998 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -121,10 +121,12 @@ std::string strSubVersion; size_t CSerializedNetMsg::GetMemoryUsage() const noexcept { - // Don't count the dynamic memory used for the m_type string, by assuming it fits in the - // "small string" optimization area (which stores data inside the object itself, up to some - // size; 15 bytes in modern libstdc++). - return sizeof(*this) + memusage::DynamicUsage(data); + return sizeof(*this) + memusage::DynamicUsage(m_type) + memusage::DynamicUsage(data); +} + +size_t CNetMessage::GetMemoryUsage() const noexcept +{ + return sizeof(*this) + memusage::DynamicUsage(m_type) + m_recv.GetMemoryUsage(); } void CConnman::AddAddrFetch(const std::string& strDest) @@ -3772,7 +3774,7 @@ void CNode::MarkReceivedMsgsForProcessing() for (const auto& msg : vRecvMsg) { // vRecvMsg contains only completed CNetMessage // the single possible partially deserialized message are held by TransportDeserializer - nSizeAdded += msg.m_raw_message_size; + nSizeAdded += msg.GetMemoryUsage(); } LOCK(m_msg_process_queue_mutex); @@ -3789,7 +3791,7 @@ std::optional> CNode::PollMessage() std::list msgs; // Just take one message msgs.splice(msgs.begin(), m_msg_process_queue, m_msg_process_queue.begin()); - m_msg_process_queue_size -= msgs.front().m_raw_message_size; + m_msg_process_queue_size -= msgs.front().GetMemoryUsage(); fPauseRecv = m_msg_process_queue_size > m_recv_flood_size; return std::make_pair(std::move(msgs.front()), !m_msg_process_queue.empty()); diff --git a/src/net.h b/src/net.h index 6b63e2cc0d1..20c654c34ab 100644 --- a/src/net.h +++ b/src/net.h @@ -245,6 +245,9 @@ public: CNetMessage(const CNetMessage&) = delete; CNetMessage& operator=(CNetMessage&&) = default; CNetMessage& operator=(const CNetMessage&) = delete; + + /** Compute total memory usage of this object (own memory + any dynamic memory). */ + size_t GetMemoryUsage() const noexcept; }; /** The Transport converts one connection's sent messages to wire bytes, and received bytes back. */ diff --git a/src/streams.cpp b/src/streams.cpp index baa5ad7abed..cd496ee2be4 100644 --- a/src/streams.cpp +++ b/src/streams.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or https://opensource.org/license/mit/. +#include #include #include #include @@ -110,3 +111,8 @@ bool AutoFile::Truncate(unsigned size) { return ::TruncateFile(m_file, size); } + +size_t DataStream::GetMemoryUsage() const noexcept +{ + return sizeof(*this) + memusage::DynamicUsage(vch); +} diff --git a/src/streams.h b/src/streams.h index e9f3562c6ce..64dbfbff145 100644 --- a/src/streams.h +++ b/src/streams.h @@ -277,6 +277,9 @@ public: { util::Xor(MakeWritableByteSpan(*this), MakeByteSpan(key)); } + + /** Compute total memory usage of this object (own memory + any dynamic memory). */ + size_t GetMemoryUsage() const noexcept; }; template