翻译:Allocating more memory than t

2018-05-31  本文已影响0人  东东东东东东丶

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 allocationovercommitment


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);

上一篇 下一篇

猜你喜欢

热点阅读