64位C++二进制文件消耗巨大的内存,即使二进制文件的大小也是巨大的
64-bit C++ binary consumes huge memory even binary size is huge
当我们用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位的移植实际上会在代码中造成很多可能的内存泄漏。
- 正在读取二进制文件(is_open)
- 在C++中将类(带有Vector成员)保存为二进制文件
- 如何从二进制文件中读取字符串
- 保存/加载大量短数组到二进制文件
- 从二进制文件中读取整数数组
- Android 在编译二进制文件时重建静态库
- 在 C++ 中将双精度变量写入二进制文件
- clang 的 libFuzzer 可以在同一二进制文件中测试超过 1 个 API 吗?
- C++:实际上不是从二进制文件中读取
- 如何从二进制文件中的给定符号中获取调用程序图
- 将内部带有矢量的结构保存/读取到二进制文件中
- 编译多个C++文件.调用二进制文件以运行代码
- 如何使用位字段将数据从二进制文件复制到结构中?
- uint8_t同一二进制文件的不同十进制值
- C++单个生成文件多个二进制文件
- 尝试将数字写入二进制文件时引发异常
- C++中读/写二进制文件
- 如何忽略某些二进制文件的执行?
- 64位C++二进制文件消耗巨大的内存,即使二进制文件的大小也是巨大的
- C++对巨大的二进制文件进行排序