我有很多建立TCP网络的类-使用boost::asio
,使用Packet
进行传输。 (Packet
的基类是std::vector<char>
)
我以为我已经解决了所有可能的内存泄漏,但是后来我在关闭客户端之前只是关闭了服务器-这应该不会造成任何问题-且_CrtDumpMemoryLeaks
报告了内存泄漏。因此,我将Visual Leaks Detector添加到了项目中,并检查了这些内存泄漏发生的位置。
void dumpMemoryLeaks(void) { CrtDumpMemoryLeaks(); }
//and in main:
atexit(dumpMemoryLeaks);
回到报告VLD内存泄漏的行,这似乎有点...对我来说很奇怪。
我有一个
AsyncAcceptor
类,我在构造函数的初始化程序列表new BoostSocket
中分配该类-原始指针(普通和SSL套接字的包装器)。在AsyncAcceptor
的析构函数中,如果原始指针有效,则将其正确删除。_acceptor = new AsyncAcceptor(service, bindIP, port); //No memory leak for this pointer
//...
_acceptor->AsyncAcceptManaged(_OnSocketAccept); //Function pointer
在
AsyncAcceptManaged
内部,服务器正在等待连接并传递另一个指针-一个内存泄漏。//Set socket properties
//Call handler function passed as parameter
handler(_socket); //Raw pointer passed to handler
_socket = nullptr;
_socket = new BoostSocket(_acceptor.get_io_service()); //with ctx for SSL, if defined
//If the acceptor is not closed, it calls `AsyncAcceptManaged` again.
现在到处理程序函数。
void OnSocketOpen(BoostSocket *sock)
{
//set additional socket options and check for error
//Note: SocketType is template parameter of class - allowing different socket types
std::shared_ptr<SocketType> newSocket(new SocketType(sock));
delete sock;
sock = nullptr;
}
SocketType
始终具有一个基类,并且BoostSocket *
具有相同的构造函数重载。Socket(BoostSocket *socket)
: _socket(std::move(*socket))
{
//...
}
在
BoostSocket
中,成员_socket是std::unique_ptr<SocketType>
,其中SocketType是tcp::socket
或boost::asio::ssl::stream<tcp::socket>
的typedef。BoostSocket(BoostSocket &&s)
: _socket(std::move(s._socket))
{ }
可视泄漏检测器指向此堆栈:
AsyncAcceptor::AsyncAcceptManaged
OnSocketOpen
-处理程序explicit shared_ptr(_Ux *_Px)
void _Resetp(_Ux *_Px)
也有微笑的“奇怪”报告。
Packet p;
//add data & add Packet to a std::queue
QueuePacket(Packet &&p);
//Inside QueuePacket:
_queue.push(std::move(p));
内存泄漏:
void push(value_type&& _Val)
void push_back(value_type&& _Val)
内存泄漏(
_socket
是std::unique_ptr
):BoostSocket(boost::asio::io_service &ioService)
: _socket(new SocketType(ioService)) //<--- here
{ }
内存泄漏(
m_Member
是std::shared_ptr
):m_Member = std::move(std::shared_ptr<StoredClass>(new StoredClass(shared_from_this()) ) );
大量内存泄漏(
_readBuffer
是std::vector<char>
):_readBuffer.resize(static_cast<std::size_t>(DataUnits::DATA_UNIT_MB) * 5); //resize to 5 MB
我认为最后一次内存泄漏是由于在内存泄漏报告时套接字未正确销毁而引起的。但是我无法想象问题可能出在哪里。我的原始指针已正确处理,对于其他任何事情,我都使用智能指针。
Visual Leak Detector detected 17 memory leaks (5244907 bytes).
这是VLD的正确报告吗? 我似乎找不到导致所有问题的内存泄漏。任何提示或解决方案表示赞赏。
最佳答案
如果您担心它是否可能是误报,则需要在调试器中循环运行程序的“核心逻辑”。每次以兆字节为单位,这应该很快确认内存是否泄漏。
关于程序的实际设计:
My raw pointers are handled properly and for anything else I use smart pointers.
...
void OnSocketOpen(BoostSocket *sock) { //set additional socket options and check for error //Note: SocketType is template parameter of class - allowing different socket types std::shared_ptr<SocketType> newSocket(new SocketType(sock)); delete sock; sock = nullptr; }
该语句和我正在采样的代码似乎彼此矛盾。
通常,对于C++ 11 / C++ 14,通常的建议是,永远不要对和处理原始指针,永远不要对对处理显式
new
或delete
关键字。显然,没有规则是100%绝对可靠的(我建议您在计算机显示器上用沙皮纸写出来),但是在这种情况下,我会说99.99 ...%的时间仍然是正确的。因此,每次处理原始指针时,如果尚未使用
std::unique_ptr
(如果它拥有对象)或std::shared_ptr
(如果有多个对象拥有),则可以将它们替换。我看到您已经对某些对象使用std::unique_ptr
和std::shared_ptr
了;确保对所有指针都执行此操作。其次,将每次使用
new
替换为适当的std::make_unique
或std::make_shared
。除非您正在编写客户删除程序,否则消除对delete
的所有引用;即使这样,也请确保这确实是您所需要的。第三,要非常注意代码的语义:
m_Member = std::move(std::shared_ptr<StoredClass>(new StoredClass(shared_from_this()) ) );
一般而言,没有理由“移动”
std::shared_ptr
。 std::shared_ptr
之所以存在,是允许指针的安全拷贝语义,并且在 Action 是适当的选择方案中,编译器通常是足够聪明来弄明白你。这段代码本身可能不错(尽管std::move是多余的),但是您可能还需要查看其他代码区域。我无法指出可能是罪魁祸首的任何特定代码(特别是因为我们此处没有完整的代码 list ),但是如果您解决了所有这些问题,很可能会解决内存泄漏。
关于c++ - “Strange”内存泄漏-TCP网络,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37923384/