我在一个相当大的SIP电话应用程序上工作,有时当我们在繁重的调用负载下使用集成的web UI (使用tntnet编写)时,程序会因为抛出std::bad_alloc而退出。有数百个线程在使用中(每个活动调用3个),所以导致异常的代码的位置是相当随机的,但总是在使用GUI之后。
现在,我知道std::bad_alloc可能会在内存不足时抛出,但在这种情况下情况并非如此。我也在想,它可以在堆损坏的时候抛出,我仍然在寻找它可能在代码库中的任何地方。
但我的问题是,除了内存不足或堆损坏之外,是否还有其他原因导致std::bad_alloc抛出?我在Linux上使用的是GNU g++。
发布于 2011-11-10 05:00:28
最有可能的是,你真的是内存不足。这将是一个非常罕见的堆损坏错误,始终只导致bad_alloc被抛出。这就像外科手术中的涂鸦一样。
这可能只是代码中的一个错误,分配了大量的内存。但您可能希望在该代码中抛出异常,至少在很大一部分时间内是这样。事实上,异常来自许多不同的地方,这与此相反。
严重的碎片可能会导致问题,特别是对于malloc实现不佳的平台。这种情况很少见,但确实会发生。
我会立即做一件事--捕获异常并调用一个保存/proc/self/maps副本的函数。这将使您对进程的内存使用峰值有一个很好的了解。您可以判断它是否接近任何平台、策略或硬件限制。
发布于 2011-11-10 05:21:32
在linux上,当前的地址空间限制可以用来人为地限制进程可以使用的内存量。您可以使用setrlimit(RLIMIT_AS, ...)手动设置此设置。这也可以使用ulimit -v在bashrc中为整个shell设置。这也可以在/etc/security/limits.conf中为整个系统设置。甚至可能在某个地方有一个/proc/sys条目,我不确定。
如果达到地址空间限制,您的进程将在尝试分配更多内存时抛出std::bad_alloc。在64位系统上,这可以是一个很好的“安全”,以确保坏的应用程序或库不会耗尽可用内存,并使系统完全交换或停止工作。确保程序本身没有在某个地方设置它,并且确保环境的其余部分也没有设置它。你可以在程序中间的某个地方插入一些代码来调用getrlimit(RLIMIT_AS, ...),以确保它不会在某个地方偷偷地出现。
一个可能更常见的原因(当然不是实际内存不足)是无符号整数绕回情况,在这种情况下,uin32_t或uint64_t用于分配内存,但从0中减去1,从而导致非常大的请求分配(以64位为单位,相当于数千be )。
无论如何,追踪这个问题的最好方法是使用GDB。如果您的应用程序根本不使用异常(因此根本没有“捕获”语句),那么您可以启用核心文件(ulimit -c unlimited)。下一次程序崩溃时,操作系统将生成一个核心文件,并将其加载到GDB中,立即给出一个回溯,显示程序崩溃的位置。
如果你有几个(但不是很多)地方使用了try,并且它捕捉到了这些坏的分配,而不是在你调试这个问题时将它们注释掉,那么你可以在GDB中运行应用程序,并在每次抛出异常时使用catch throw命令让GDB中断。为了让这两种方法都能正常工作,永远不要使用-fomit-frame-pointer编译,而要始终使用-ggdb编译(即使使用-O3)。
https://stackoverflow.com/questions/8071428
复制相似问题