为什么进程会在4GB时被终止?

5
我编写了一个程序,可用于大量数据的处理。我的CPU和操作系统(Ubuntu)都是64位的,我有4GB的RAM。使用“top”命令(%Mem字段),我发现该进程的内存占用率最高达到了约87%即3.4+ GB,然后它就被终止了。
然后我使用“uname -m”命令检查了进程可以访问多少内存,结果显示为“不限制”。
既然操作系统和CPU都是64位的,并且存在交换分区,那么操作系统应该已经使用了虚拟内存,即[ > 3.4GB + yGB来自交换空间]的总量,只有当进程需要更多的内存时,才会被杀死。
所以,我有以下问题:
  1. 在64位机器上,理论上进程可以访问多少物理内存?我的答案是2^48字节。
  2. 如果物理内存不足2^48字节,则操作系统应该使用虚拟内存,对吗?
  3. 如果上述问题的答案是肯定的,那么操作系统应该使用SWAP空间,为什么它没有使用,而是直接杀掉了进程?我认为我们不必在编写程序时使用某些特定的系统调用来实现这一点。
请给予建议。

2^48字节是总可寻址空间,一个进程不能使用全部空间——内核地址空间也必须适应其中。它会被OOM killer杀掉吗? - fge
3
这个应用程序是否编译为64位?在64位系统上运行的32位应用程序仍然受到4GB内存限制的影响。 - Marc B
另外,你如何分配?mmap、malloc、shm、其他还是全部? - fge
@fge:是的,它被OOM杀死了。我从内核日志中检查过了。 - Piyush Kansal
@MarcB:是的,它是64位可执行文件。 - Piyush Kansal
@fge:我基本上使用了两种数据结构,向量和哈希表。我没有使用C++的哈希映射,而是自己实现了它。在那里,我使用new进行分配。但是,我确定哈希表不是问题,因为它不会超过400 MB。问题出在向量(类型为字符串)上。 - Piyush Kansal
3个回答

2

问题不仅是数据大小。例如,执行ulimit -a并检查最大堆栈大小。您是否有一个杀死原因?设置“ulimit -c 20000”以获取核心文件,使用gdb进行检查时会显示原因。


嗯,这可能会有所帮助。实际上,我正在使用一个vector<string>,它是一个局部变量。而且这个向量包含大量的数据。但是,作为STL,我认为它的内存需求必须使用堆而不是栈来满足。如果是这种情况,最大栈段大小就不重要了。你有什么建议? - Piyush Kansal
@ott-- OOM killer,参见问题评论。调整它真是个麻烦事 :/ - fge
页面http://en.wikipedia.org/wiki/Out_of_memory的末尾有一些文章链接,介绍如何处理oom killer。 - ott--

1

使用fileldd检查您的可执行文件确实是64位的。

还要检查资源限制。从进程内部,您可以使用getrlimit系统调用(以及setrlimit在可能时更改它们)。从bash shell中,尝试ulimit -a。从zsh shell中尝试limit

还要检查您的进程确实消耗了您认为它消耗的内存。如果其pid为1234,则可以尝试pmap 1234。从进程内部,您可以读取/proc/self/maps/proc/1234/maps(可以从终端读取)。还有/proc/self/smaps/proc/1234/smaps以及/proc/self/status/proc/1234/status和其他文件在您的/proc/self/中...

使用free命令检查你认为的内存(和交换空间)是否正确。你可以使用swapon /tmp/someswapfile添加一些临时交换空间(并使用mkswap进行初始化)。

几个月(甚至几年)前,我通常能够在具有8Gb RAM的机器上,在Gnu/Linux/Debian/Sid/AMD64下运行一个7Gb的进程(一个巨大的cc1编译)。

你可以尝试使用一个小的测试程序,例如使用malloc分配几个32Mb大小的内存块。不要忘记在里面写入一些字节(至少每个兆字节)。

标准的C++容器,如std::mapstd::vector,据说消耗的内存比我们通常想象的要多。

如果需要,购买更多的RAM。现在这很便宜。


我实际上怀疑(并且我已经被告知)std::vector具有重大开销。我无法更具体,因为我没有深入研究libstdc++源代码(它位于GCC内部)。 - Basile Starynkevitch
正如我之前提到的,uname显示的内存限制是“无限制”。还有其他需要我检查的吗?你关于pmap和/proc/self/*的建议很好。我会尝试一下。我也可以尝试使用swapon。但这也是我的一个问题,为什么操作系统本身不使用虚拟内存来处理它。程序员需要担心什么?在你的情况下,这很有道理,因为你有8GB,而进程需要7GB。我的情况恰恰相反。当我已经有一个在4GB时就崩溃的程序时,不确定malloc如何帮助我。 - Piyush Kansal
STL使用更多内存可能是一个问题。这是需要考虑的一个好点。购买RAM肯定是一个选择。但是这个问题的重点是要找出对我来说未知的“某些东西”,或者说如何从我的硬件中提取最大值 :) - Piyush Kansal
1
STL可能会增加负担。但问题是为什么操作系统不使用交换空间。 - Piyush Kansal
让我们在聊天中继续这个讨论:http://chat.stackoverflow.com/rooms/6293/discussion-between-basile-starynkevitch-and-piyush-kansal - Basile Starynkevitch
显示剩余2条评论

0

在编程中,所有东西都必须适应它,包括你的图形适配器、操作系统内核、BIOS等等。而且,可以寻址的数量也不能通过SWAP来扩展。

值得注意的是,进程本身也需要是64位的。如果你在使用过多的RAM,一些操作系统可能会变得不稳定,从而终止该进程。


当然,我理解。而且该过程也是64位的。 - Piyush Kansal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接