I have an application that receives packets at a fast rate, and every time it receives packets, some objects are created to handle them and for the object creation I am using std::unique_ptr
.
For some reason they don't seem to be getting cleaned up properly as I can see the memory usage of the application constantly rise.
I took a snapshot to see where the allocations are coming from and it was as expected
Here is the code that is creating these PacketIn
and PacketHeader
objects
while (!server->BufferEmpty()) {
std::shared_ptr<Stream> inStream = std::make_shared<Stream>();
std::vector<unsigned char> buffer = inStream->GetBuffer();
std::size_t n = server->receive(boost::asio::buffer(buffer),
boost::posix_time::milliseconds(-1), ec);
if (ec)
{
std::cout << "Receive error: " << ec.message() << "\n";
}
else
{
std::unique_ptr<IPacketIn> incomingPacket = std::make_unique<IPacketIn>();
incomingPacket->ReadHeader(inStream);
std::cout << "Received a buffer! ";
//std::cout.write(buffer, n);
std::cout << "\n";
incomingPacket.reset();
}
++packetsRead;
inStream.reset();
}
PacketIn
class IPacketIn {
public:
IPacketIn() {
m_packetHeader = std::make_unique<PacketHeader>();
}
~IPacketIn() {
m_packetHeader.reset();
}
void ReadHeader(std::shared_ptr<Stream> stream) {
m_packetHeader->ReadHeader(stream);
}
private:
std::unique_ptr<IPacketHeader> m_packetHeader;
};
PacketHeader
class PacketHeader : public IPacketHeader {
public:
PacketHeader() {
}
~PacketHeader() {
}
void ReadHeader(std::shared_ptr<Stream> stream) override {
//m_uuid = stream->ReadUUID(10);
//m_timestamp = stream->ReadInt64();
//m_packetId = stream->ReadShort();
}
private:
std::string m_uuid;
//long m_timestamp;
//unsigned short m_packetId;
I've stepped through the code and it seems calling reset is clearing the unique_ptr
but is it actually deleting the memory it has created or am I missing something?
Edit
So it seems it is not related to the unique_ptr
as I have tried swapping to using new
and delete
with the same issue.
What I have noticed is that the issue occurs when the PacketHeader
class has member variables
std::string m_uuid;
long m_timestamp;
unsigned short m_packetId;
When these variables are removed, the issue no longer occurs.
I have narrowed it down to being the std::string uuid;
. When this is present in the PacketHeader
class it causes the memory to rise but when it is removed it is fine. Why is this?
Are these somehow not being removed when the object is destroyed?
It turns out that ownership of instances of PacketHeader
class is held through a pointer to base class IPacketHeader
which lacks a virtual destructor. So the std::unique_ptr<IPacketHeader>
was unable to perform cleanup properly.
Yes, it is deleting the memory.
Note that neither of the calls to reset
are needed - the destructor of the pointer is about to be called in both cases, and that will delete the memory.
Note that monitoring process memory is a very unreliable way to tell if you have a memory leak. Up to some limit, system libraries quite often try not to reuse recently released memory - in order to reduce the impact of use-after-free bugs.
Try using valgrind to see if you have an actual memory leak.
Edit: VTT has clarified that the OP wasn't just monitoring process memory, but using VS memory profiler (which is very similar to valgrind).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With