为什么通过 unique_ptr 创建的内存在调用 reset() 时没有被正确删除?
Why is the memory created via unique_ptr not being deleted properly when reset() is called?
我有一个应用程序可以快速接收数据包,每次它接收数据包时,都会创建一些对象来处理它们,我正在使用 std::unique_ptr
.
创建对象
出于某种原因,它们似乎没有得到正确清理,因为我可以看到应用程序的内存使用量不断上升。
我拍了一张快照以查看分配的来源,正如预期的那样
这是创建这些 PacketIn
和 PacketHeader
对象的代码
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;
我已经逐步完成了代码,似乎调用重置正在清除 unique_ptr
但它实际上是在删除它创建的内存还是我遗漏了什么?
编辑
所以它似乎与 unique_ptr
无关,因为我曾尝试使用 new
和 delete
来解决同样的问题。
我注意到当 PacketHeader
class 有成员变量时会出现问题
std::string m_uuid;
long m_timestamp;
unsigned short m_packetId;
删除这些变量后,问题不再出现。
我已将其缩小为 std::string uuid;
。当它出现在 PacketHeader
class 中时,它会导致内存增加,但当它被删除时就没问题了。这是为什么?
当对象被销毁时,这些是否以某种方式没有被删除?
是的,是删除内存
请注意,对 reset
的调用都不需要 - 在这两种情况下都将调用指针的析构函数,这将删除内存。
请注意,监视进程内存是判断是否存在内存泄漏的一种非常不可靠的方法。在某种程度上,系统库经常尝试 不 重用最近释放的内存 - 以减少释放后使用错误的影响。
尝试使用 valgrind 查看是否有实际内存泄漏。
编辑:VTT 已阐明 OP 不是 只是监视进程内存,而是使用 VS 内存分析器(这与 valgrind 非常相似)。
事实证明,PacketHeader
class 实例的所有权是通过指向缺少虚拟析构函数的基 class IPacketHeader
的指针持有的。因此 std::unique_ptr<IPacketHeader>
无法正确执行清理。
我有一个应用程序可以快速接收数据包,每次它接收数据包时,都会创建一些对象来处理它们,我正在使用 std::unique_ptr
.
出于某种原因,它们似乎没有得到正确清理,因为我可以看到应用程序的内存使用量不断上升。
我拍了一张快照以查看分配的来源,正如预期的那样
这是创建这些 PacketIn
和 PacketHeader
对象的代码
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;
我已经逐步完成了代码,似乎调用重置正在清除 unique_ptr
但它实际上是在删除它创建的内存还是我遗漏了什么?
编辑
所以它似乎与 unique_ptr
无关,因为我曾尝试使用 new
和 delete
来解决同样的问题。
我注意到当 PacketHeader
class 有成员变量时会出现问题
std::string m_uuid;
long m_timestamp;
unsigned short m_packetId;
删除这些变量后,问题不再出现。
我已将其缩小为 std::string uuid;
。当它出现在 PacketHeader
class 中时,它会导致内存增加,但当它被删除时就没问题了。这是为什么?
当对象被销毁时,这些是否以某种方式没有被删除?
是的,是删除内存
请注意,对 reset
的调用都不需要 - 在这两种情况下都将调用指针的析构函数,这将删除内存。
请注意,监视进程内存是判断是否存在内存泄漏的一种非常不可靠的方法。在某种程度上,系统库经常尝试 不 重用最近释放的内存 - 以减少释放后使用错误的影响。
尝试使用 valgrind 查看是否有实际内存泄漏。
编辑:VTT 已阐明 OP 不是 只是监视进程内存,而是使用 VS 内存分析器(这与 valgrind 非常相似)。
事实证明,PacketHeader
class 实例的所有权是通过指向缺少虚拟析构函数的基 class IPacketHeader
的指针持有的。因此 std::unique_ptr<IPacketHeader>
无法正确执行清理。