当我检查我的应用程序是否有内存泄漏时,我遇到了valgrind非常特殊的行为。据我所知,他看到以下代码
virtual ServiceHandler* createServiceHandler(StreamSocket& socket)
/// Create and initialize a new ServiceHandler instance.
///
/// Subclasses can override this method.
{
return new ServiceHandler(socket, *_pReactor);
}
作为我分配和释放记忆的地方。此代码是POCO库的一部分,可以找到它here。下面是来自valgrind的log的一个例子,说明提供的return语句同时产生new和delete。
Invalid read of size 8
==9764== at 0x1C63DC: Poco::Net::Socket::operator!=(Poco::Net::Socket const&) const (Socket.h:340)
==9764== by 0x1C2A5C: SocketHandler::onReadableNotification(Poco::AutoPtr<Poco::Net::ReadableNotification> const&) (SocketHandler.cpp:67)
==9764== by 0x1CA0DF: Poco::NObserver<SocketHandler, Poco::Net::ReadableNotification>::notify(Poco::Notification*) const (NObserver.h:88)
==9764== by 0x5C04077: Poco::NotificationCenter::postNotification(Poco::AutoPtr<Poco::Notification>) (NotificationCenter.cpp:78)
==9764== by 0x579F422: Poco::Net::SocketNotifier::dispatch(Poco::Net::SocketNotification*) (SocketNotifier.cpp:80)
==9764== by 0x579C0DC: Poco::Net::SocketReactor::dispatch(Poco::AutoPtr<Poco::Net::SocketNotifier>&, Poco::Net::SocketNotification*) (SocketReactor.cpp:282)
==9764== by 0x579BEE1: Poco::Net::SocketReactor::dispatch(Poco::Net::Socket const&, Poco::Net::SocketNotification*) (SocketReactor.cpp:258)
==9764== by 0x579B5F4: Poco::Net::SocketReactor::run() (SocketReactor.cpp:114)
==9764== by 0x5C50406: Poco::(anonymous namespace)::RunnableHolder::run() (Thread.cpp:57)
==9764== by 0x5C500E0: Poco::ThreadImpl::runnableEntry(void*) (Thread_POSIX.cpp:349)
==9764== by 0x6D20493: start_thread (pthread_create.c:333)
==9764== by 0x78BBAFE: clone (clone.S:97)
==9764== Address 0x10c8f908 is 40 bytes inside a block of size 352 free'd
==9764== at 0x4C2D2DB: operator delete(void*) (vg_replace_malloc.c:576)
==9764== --> by 0x19D1CD: Poco::Net::SocketAcceptor<SocketHandler>::createServiceHandler(Poco::Net::StreamSocket&) (SocketAcceptor.h:166)
==9764== by 0x19B3E3: Poco::Net::SocketAcceptor<SocketHandler>::onAccept(Poco::Net::ReadableNotification*) (SocketAcceptor.h:157)
==9764== by 0x1A1385: Poco::Observer<Poco::Net::SocketAcceptor<SocketHandler>, Poco::Net::ReadableNotification>::notify(Poco::Notification*) const (Observer.h:86)
==9764== by 0x5C04077: Poco::NotificationCenter::postNotification(Poco::AutoPtr<Poco::Notification>) (NotificationCenter.cpp:78)
==9764== by 0x579F422: Poco::Net::SocketNotifier::dispatch(Poco::Net::SocketNotification*) (SocketNotifier.cpp:80)
==9764== by 0x579C0DC: Poco::Net::SocketReactor::dispatch(Poco::AutoPtr<Poco::Net::SocketNotifier>&, Poco::Net::SocketNotification*) (SocketReactor.cpp:282)
==9764== by 0x579BEE1: Poco::Net::SocketReactor::dispatch(Poco::Net::Socket const&, Poco::Net::SocketNotification*) (SocketReactor.cpp:258)
==9764== by 0x579B5F4: Poco::Net::SocketReactor::run() (SocketReactor.cpp:114)
==9764== by 0x5C50406: Poco::(anonymous namespace)::RunnableHolder::run() (Thread.cpp:57)
==9764== by 0x5C500E0: Poco::ThreadImpl::runnableEntry(void*) (Thread_POSIX.cpp:349)
==9764== by 0x6D20493: start_thread (pthread_create.c:333)
==9764== Block was alloc'd at
==9764== at 0x4C2C21F: operator new(unsigned long) (vg_replace_malloc.c:334)
==9764== --> by 0x19D19E: Poco::Net::SocketAcceptor<SocketHandler>::createServiceHandler(Poco::Net::StreamSocket&) (SocketAcceptor.h:166)
==9764== by 0x19B3E3: Poco::Net::SocketAcceptor<SocketHandler>::onAccept(Poco::Net::ReadableNotification*) (SocketAcceptor.h:157)
==9764== by 0x1A1385: Poco::Observer<Poco::Net::SocketAcceptor<SocketHandler>, Poco::Net::ReadableNotification>::notify(Poco::Notification*) const (Observer.h:86)
==9764== by 0x5C04077: Poco::NotificationCenter::postNotification(Poco::AutoPtr<Poco::Notification>) (NotificationCenter.cpp:78)
==9764== by 0x579F422: Poco::Net::SocketNotifier::dispatch(Poco::Net::SocketNotification*) (SocketNotifier.cpp:80)
==9764== by 0x579C0DC: Poco::Net::SocketReactor::dispatch(Poco::AutoPtr<Poco::Net::SocketNotifier>&, Poco::Net::SocketNotification*) (SocketReactor.cpp:282)
==9764== by 0x579BEE1: Poco::Net::SocketReactor::dispatch(Poco::Net::Socket const&, Poco::Net::SocketNotification*) (SocketReactor.cpp:258)
==9764== by 0x579B5F4: Poco::Net::SocketReactor::run() (SocketReactor.cpp:114)
==9764== by 0x5C50406: Poco::(anonymous namespace)::RunnableHolder::run() (Thread.cpp:57)
==9764== by 0x5C500E0: Poco::ThreadImpl::runnableEntry(void*) (Thread_POSIX.cpp:349)
==9764== by 0x6D20493: start_thread (pthread_create.c:333)
我将-->
添加到有趣的部分。
一旦发生这种情况,我会观察到更多类似的日志,因为对象似乎没有被分配。在看到此错误之前,应用程序正常工作了一段时间,这是第一个发生的错误。我认为当套接字行为不好时可能会发生此错误。
我使用以下命令对应用程序进行valgrind
valgrind --vgdb=yes --vgdb-error=0 app
并使用gdb进一步检查代码。
我的问题是:
@edit
构造函数
SocketHandler::SocketHandler(StreamSocket &socket, SocketReactor &reactor) :
_socket(socket) /* copy */, _reactor(reactor) /* reference */ {
_socket.setBlocking(false);
_reactor.addEventHandler(_socket, NObserver<SocketHandler, ReadableNotification>(*this,
&SocketHandler::onReadableNotification));
_reactor.addEventHandler(_socket,
NObserver<SocketHandler, ErrorNotification>(*this, &SocketHandler::onErrorNotification));
_reactor.addEventHandler(_socket, NObserver<SocketHandler, ShutdownNotification>(*this,
&SocketHandler::onShutdownNotification));
_addr = _socket.peerAddress().toString();
}
答案 0 :(得分:1)
Valgrind消息并不表示您在同一行代码中有新消息和删除消息。
valgrind错误消息包含3个堆栈跟踪。
第一个堆栈跟踪是检测到错误的位置。此错误包括读取已释放的内存。
然后,Valgrind试图为您提供有关此内存的更多信息。 为此,它会显示2个额外的堆栈跟踪:第二个堆栈跟踪指示释放此内存的位置。 第三个堆栈跟踪指示这块内存的分配位置。
换句话说:你的代码首先分配了一块内存(at 堆栈跟踪nr 3)。然后你的代码释放了这段内存(在堆栈跟踪nr 2)。 然后你的代码错误地访问了这块内存(在堆栈跟踪nr 1处)。
所以,这看起来就像你有一个真正的错误:你正在使用一个悬空指针,指向已释放的内存。
您可能必须查看生成的代码,以确切了解为createServiceHandler调用生成了对new / delete的调用。 显然,'new'和'delete'堆栈跟踪中有2条不同的指令(0x19D1CD和0x19D19E)。
答案 1 :(得分:0)
正如Bo Persson在评论中所建议的,删除是由构造函数中的未处理异常引起的。在ctor中捕获相关异常之后,在负责注册事件处理程序的行之前移动抛出异常的表达式
SocketHandler::SocketHandler(Poco::Net::StreamSocket &socket, SocketReactor &reactor) :
_socket(socket), _reactor(reactor) {
try {
_socket.setBlocking(false);
_addr = _socket.peerAddress().toString();
_reactor.addEventHandler(_socket, NObserver<SocketHandler, ReadableNotification>(*this,
&SocketHandler::onReadableNotification));
_reactor.addEventHandler(_socket,
NObserver<SocketHandler, ErrorNotification>(*this,
&SocketHandler::onErrorNotification));
_reactor.addEventHandler(_socket, NObserver<SocketHandler, ShutdownNotification>(*this,
&SocketHandler::onShutdownNotification));
} catch (Exception& e) {
// Handle POCO exception
} catch (...) {
// Handle ellipsis
}
}
无效的内存访问不再存在。尝试获取不再连接的套接字地址时,_socket.peerAddress()
抛出异常。起初我认为ctor中的任何异常都会导致应用程序迅速崩溃,但在Poco::Net::SocketReactor
中,每个未处理的异常都会传递给ErrorHandler
。这就是为什么应用程序在抛出未处理的异常后仍然继续工作的原因。可以找到引用的代码here:126。