Stack overflow地址:c++ - Allocating more memory than there exists using malloc - Stack Overflow
翻译:
下面的代码片段,每次从stdin中读取到字母'u'时就会分配2Gb的内存,一旦读取到'a'就会初始化所有分配的内存。
#include
#include
#include
#include
#define bytes 2147483648
using namespace std;
int main()
{
char input [1];
vector activate;
while(input[0] != 'q')
{
gets (input);
if(input[0] == 'u')
{
char *m = (char*)malloc(bytes);
if(m == NULL) cout << "cant allocate mem" << endl;
else cout << "ok" << endl;
activate.push_back(m);
}
else if(input[0] == 'a')
{
for(int x = 0; x < activate.size(); x++)
{
char *m;
m = activate[x];
for(unsigned x = 0; x < bytes; x++)
{
m[x] = 'a';
}
}
}
}
return 0;
}
我在一台有3Gb内存的linux虚拟机上运行这个代码。在使用htop工具监测系统内存使用情况,我意识到malloc操作并不影响资源。
举个例子,当我只输入一次'u'时(分配2Gb的堆内存),我没有在htop上看到内存使用增加2Gb。只有当我输入'a'(初始化)时,我才看到内存使用的增加。
因此,我可以“malloc”比实际更多的堆内存。举个例子,我可以malloc 6GB(这远大于我的ram和交换内存)并且malloc允许这么做(malloc没有返回NULL)。但是当我尝试初始化分配的内存时,我可以看到内存和交换内存被填满直到进程被杀死。
我的问题:
1.这是内核的bug吗?
2.能有人给我解释下,为什么这种行为是允许的?
Answers1:
这叫 memory overcommit.。你可以以root用户关闭它:
echo 2 > /proc/sys/vm/overcommit_memory
这不是我喜欢的内核特性(所以我经常关闭它),看malloc(3)和 mmap(2)、proc(5)。
NB:echo 0代替echo 2并不总是可行的。详情看文档(尤其是我连接的 proc man文档)
Answers2:
malloc的man文档(online here):
默认的,Linux遵从积极的内存分配策略。这意味着当 malloc()返回非NULL时,并不保证内存时真正可用的。
因此当你想要分配更多的时候,它在骗你,当你想要使用分配的内存时,它会为你尝试寻找足够的内存如果找不到足够内存它可能就会崩溃。
Answers3:
不,这不是内核的bug。你已经发现了一些知识被称为延迟页面(或者过量使用)。
直到你写一个字节到使用malloc()分配的地址时,内核做的就是保留地址范围。这取决于你内存分配器和操作系统的实现,但是大多数内核在内存第一次使用之前不会触发过大的开销。
实时操作系统像VxWorks不会允许这种行为,因为延迟页面导致严重的延迟。技术上,它就是将延迟延迟到稍晚的一个不确定的时间。
对于更多细节的讨论,你可能会对IBM's AIX操作系统的处理方式感兴趣,page allocation,overcommitment。
Answers4:
这个结果是Basile提到的,过量使用内存。然而,这有一种有趣的解释。
基本上,当时尝试在Linux(POSIX)上映射一块额外的内存时,内核仅仅保留它,只有你的应用程序访问其中一个保留页时才会最终使用它。这允许多个应用程序保留超过实际的 ram/swap的内存。
这是一个令人满意的特性在大多数Linux环境中,除非你有一个实时操作系统或者在那些你确切的知道谁会需要资源,什么时候以及为什么。
否则一个人可能一起过来,malloc超过ram内存的总量(实际上对它什么也不做)。
另一个例子是mmap()的懒分配,在那里你有一个文件的虚拟映射放在里面,但是你只有一小块真正的内存用于这项工作。这将允许你mmap()一个巨大的文件(比你可用的RAM还要大),并且使用它就像正常的文件句柄那样,这是非常玩么的。
Answers5:
在使用内存的时候应该这么做:
memset(m, 0, bytes);
你也可以使用calloc,它不仅分配内存并且用0来填充它:
char* m = (char*) calloc(1, bytes);
网友评论