在 32 位 Linux 中无法耗尽物理内存
Posted
技术标签:
【中文标题】在 32 位 Linux 中无法耗尽物理内存【英文标题】:Cannot Exhaust Physical Memory in 32 bit Linux 【发布时间】:2018-05-02 16:30:23 【问题描述】:所以我有一个有趣的基于操作系统的问题给你。在过去的几个小时里,我一直在与我认识的任何有 C 编程经验的人交谈,但似乎没有人能够就为什么会发生这种行为提出明确的答案。
我有一个故意设计为导致严重内存泄漏的程序(例如,当您在分配内存后不释放内存时会发生什么情况)。在 64 位操作系统(Windows、Linux 等)上,它会做它应该做的事情。它填充物理内存,然后填充操作系统的交换空间。在 Linux 中,该进程随后被操作系统终止。然而,在 Windows 中,它不是,它会继续运行。最终的结果是系统崩溃。
代码如下:
#include <stdlib.h>
#include <stdio.h>
void main()
while(1)
int *a;
a = (int*)calloc(65536, 4);
但是,如果您在 32 位 Linux 发行版上编译并运行此代码,则它对物理内存的使用完全没有影响。它使用了我分配的 4 GB RAM 的大约 1%,之后就再也没有增加。我没有要测试的 32 位 Windows 的合法副本,所以我不能确定这也发生在 32 位 Windows 上。
谁能解释一下为什么使用 calloc 会填满 64 位 Linux 操作系统的物理内存,而不是 32 位 Linux 操作系统?
【问题讨论】:
这是 Linux 的一个“特性”。您可以根据需要分配尽可能多的内存,只要您实际上不使用它。尝试在您分配的内存中写入一个随机字节,您将看到您的系统很快就会开始终止随机进程。 你永远不会使用内存。这可以在多个级别上捕获。编译器已经可以消除代码,它没有可观察到的行为。操作系统可能会延迟页面分配,直到出现页面错误。等等...要查看某些内容,请使用0
以外的一些数据填充内存,这可能是一种特殊情况。
好的,我可以修改它以使用 malloc 和 for 循环遍历分配值的数组,这是其他人所做的,它会产生相同的结果。其次,这并不能解释为什么这段代码将填充 64 位 Linux 操作系统的主内存。
名称是overcommiting。
我也不认为过度使用是我在这里遇到的问题。我的物理台式电脑有 16 GB 的 RAM。此虚拟机使用 4 GB。 en.wikipedia.org/wiki/Memory_overcommitment
【参考方案1】:
malloc
和 calloc
函数在技术上并不分配内存,尽管它们的名称。它们实际上为您的程序地址空间的一部分分配了操作系统级别的读/写权限。这是一个细微的差别,大部分时间并不相关。
这个程序,正如所写的,只消耗地址空间。最终,calloc
将开始返回 NULL,但程序将继续运行。
#include <stdlib.h>
// Note main should be int.
int main()
while (1)
// Note calloc should not be cast.
int *a = calloc(65536, sizeof(int));
如果你写入从 calloc 返回的地址,它将强制内核分配内存来支持这些地址。
#include <stdlib.h>
#include <string.h>
int main()
size_t size = 65536 * 4;
while (1)
// Allocates address space.
void *p = calloc(size, 1);
// Forces the address space to have allocated memory behind it.
memset(p, 0, size);
仅写入从calloc
返回的块中的单个位置是不够的,因为分配实际内存的粒度是 4 KiB(页面大小...... 4 KiB 是最常见的)。因此,您只需写入每一页即可。
64 位的情况如何?
分配地址空间需要一些记账开销。在 64 位系统上,您会获得 40 或 48 位的地址空间,其中大约一半可以分配给程序,即至少 8 TiB。在 32 位系统上,这达到 2 GiB 左右(取决于内核配置)。
因此,在 64 位系统上,您可以分配 ~8 TiB,而在 32 位系统上,您可以分配 ~2 GiB,而开销是导致问题的原因。每次调用malloc
或calloc
通常都会产生少量开销。
另见Why malloc+memset is slower than calloc?
【讨论】:
如果这是真的,那为什么它会淹没物理内存并最终淹没 64 位操作系统的交换空间? @LC14199 因为这就是现代内存管理的完成方式。您分配的内存是虚拟的,直到您实际写入它,然后需要一个物理页面(实际的内存块)并且 RAM 使用量会增加。拿一本操作系统书籍,阅读内存管理一章。 @TonyTannous,calloc 在分配内存后写入内存。它使用 0 值初始化所有内存。因此,这使得内存不再是虚拟的。或者至少,我目前是这样理解的。 @LC14199:这是不正确的。calloc
在分配内存后并不总是写入内存。
tutorialspoint.com/c_standard_library/c_function_calloc.htm 根据本页的定义,“malloc 和 calloc 的区别在于 malloc 不会将内存设置为零,而 calloc 会将分配的内存设置为零。”所以现在我很想知道它到底是如何工作的。我现在正在测试你的代码。然后当然是这个:***.com/questions/1538420/…以上是关于在 32 位 Linux 中无法耗尽物理内存的主要内容,如果未能解决你的问题,请参考以下文章