64位C++二进制文件消耗巨大的内存,即使二进制文件的大小也是巨大的

64-bit C++ binary consumes huge memory even binary size is huge

本文关键字:巨大 二进制文件 内存 C++ 64位      更新时间:2023-10-16

当我们用32位编译C++应用程序时,一切都还可以。当我们将所有应用程序移植到64位时,二进制大小增加了一倍多!当我们运行二进制文件时,只有一个运行,因为它占用了所有的RAM。我们已经完成了所有的64位移植,所以编译是成功的。然而,在运行时,内存消耗会达到极限。不过它不会崩溃。它只是运行,直到它停止,并且没有生成核心文件。有人建议我从哪里开始调查这件事吗?

我们的编译选项是:

-D_linux_-phread-fexceptions-c-Wall-DSTL_AS_DEFAULT_ARGS-DUsePthread-D_REENTRANT-Dx86_64-DLINUX-g-O2

我们linux机器上的ulimit信息是:

-bash-4.1$ ulimit -a
core file size          (blocks, -c) unlimited
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 30405
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 4096
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 4096
cpu time               (seconds, -t) unlimited
max user processes              (-u) 10240
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

我们的24个二进制文件总共创建了大约4000个线程(因此-u 10240),这些线程主要用于消息侦听。它还不断地搜索/维护数据库连接。堆栈大小-s之前是512,但我们改为4096只是为了尝试,但仍然存在问题。这也可能是我们需要修复的内存泄漏,因为在移植到64位时出现了一些未检测到的逻辑错误,但我不确定从哪里开始。关于如何解决这个问题,有什么建议吗?

编译器:g++(GCC)4.4.7 20120313(Red Hat 4.4.7-3)OS:COS 6.4版

正如您在注释中所报告的,可执行文件中有很多符号。很可能您使用了许多链接了调试信息的模板。strip可以减少这种情况,也可以使用链接器标志。

最大的问题不在于可执行文件的大小您正在实例化的线程数量惊人。除非你在拥有数千个CPU的超级计算机上运行,否则你应该(必须)重新设计你的程序,以使用更少的线程。

每个线程都有自己的堆栈,堆栈大小乘以10240会占用大量内存。

在给定的系统上也可以运行数量有限的线程。

额外的好处是,一个线程数量合理的程序会运行得更快。您的工作线程不应超过N个(N=逻辑核心计数)。

编辑:

如果每个线程都要执行大量的I/O(这是一种阻塞操作),则可以使用更多的线程(最多2N个)。例如,当使用1.5N内核时,C++代码的编译会更快,因为编译需要大量I/O。

好的,谢谢大家的建议。问题出在软件的代码中。当移植到64位时,这是一个错误。在C++中处理str.find()时,代码使用无符号int而不是size_t。unsigned int是32位,而size_t是64位。

http://www.cplusplus.com/reference/string/string/find/

size_t find(const字符串&str,size_t pos=0)const;

while()循环(见下文)的计算结果总是为true,因为当-1被传递给无符号int(见第B行)时,它将成为32位无符号int的最高值。它永远不会等于64位的size_t的最高值npos。因此,无限循环会导致非常高的CPU使用率,加上无限push_back()会导致非常大的内存。

http://www.cplusplus.com/reference/string/string/npos/

上面写着:该常量(std::string::npos)的定义值为-1,因为size_t是一个无符号整数类型,所以它是该类型可能表示的最大值。

**//unsigned int strPos1 = 0;
**//unsigned int strPos2 = 0;
size_t strPos1 = 0;
size_t strPos2 = 0;
Line A       **while ( strPos2 != str.npos )**
{
Line B         **strPos2 = str.find( ",", strPos1 );**
tokens.push_back(str.substr(strPos1, strPos2 - strPos1));
strPos1 = strPos2 + 1;
}

我将不得不检查其他二进制文件中是否存在类似的情况,因为它们也存在内存泄漏。这种从32位到64位的移植实际上会在代码中造成很多可能的内存泄漏。