分配比使用malloc存在的内存更多的内存

Mik*_*e G 8 c c++ linux memory memory-management

每次从stdin读取字母'u'时,此代码段将分配2Gb,并在读取'a'时初始化所有已分配的字符.

#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <vector>
#define bytes 2147483648
using namespace std;
int main()
{
    char input [1];
    vector<char *> 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;
}
Run Code Online (Sandbox Code Playgroud)

我在具有3Gb内存的Linux虚拟机上运行此代码.在使用htop工具监视系统资源使用情况时,我意识到malloc操作没有反映在资源上.

例如,当我只输入'u'一次(即分配2GB的堆内存)时,我看不到内存使用量在htop中增加了2GB.只有当我输入'a'(即初始化)时,才会看到内存使用量的增加.

因此,我能够"malloc"存在比存在更多的堆内存.例如,我可以使用malloc 6GB(这比我的内存和交换内存更多)和malloc允许它(即malloc不返回NULL).但是当我尝试初始化分配的内存时,我可以看到内存和交换内存填满,直到进程被终止.

- 我的问题:

这是一个内核错误吗?

有人可以向我解释为什么允许这种行为?

Bas*_*tch 14

它被称为内存过量使用.您可以通过以root身份运行来禁用它:

 echo 2 > /proc/sys/vm/overcommit_memory
Run Code Online (Sandbox Code Playgroud)

它不是我喜欢的内核功能(所以我总是禁用它).参见malloc(3)mmap(2)以及proc(5)

注意:echo 0而不是echo 2 经常 - 但不总是 - 也工作.阅读文档(特别proc是我刚刚链接到的手册页).


mAS*_*OUD 10

来自man malloc(在线):

默认情况下,Linux遵循乐观的内存分配策略.这意味着当malloc()返回非NULL时,无法保证内存确实可用.

因此,当你只是想分配太多时,它"谎言"给你,当你想使用分配的内存时,它会尝试为你找到足够的内存,如果它找不到足够的内存,它可能会崩溃.


And*_*man 5

不,这不是内核错误.您发现了一些称为延迟分页(或过度使用)的内容.

直到你用malloc (...)内核分配的地址写一个字节,只是"保留"地址范围.这当然取决于内存分配器和操作系统的实现,但是在首次使用内存之前,大多数好的内核都不会产生大部分内核开销.

囤积分配器是一个立即想到的大罪犯,通过广泛的测试我发现它几乎从不利用支持延迟分页的内核.如果在分配后立即对整个内存范围进行零填充,则可以始终减轻任何分配器中延迟分页的影响.

像VxWorks这样的实时操作系统永远不会允许这种行为,因为后期分页会引入严重的延迟.从技术上讲,它所做的只是将延迟关闭,直到稍后的不确定时间.

有关更详细的讨论,您可能有兴趣了解IBM的AIX操作系统如何处理页面分配过度使用.