Linux上的C程序耗尽内存

时间:2009-12-08 08:26:52

标签: c linux memory-management

我想编写一个程序来消耗所有可用的内存来理解结果。我听说linux一旦无法分配内存就开始杀死进程。

任何人都可以帮我解决这个问题。

我写了以下内容,但内存似乎没有用尽:

#include <stdlib.h>

int main()
{
        while(1)
        {
                malloc(1024*1024);
        }
        return 0;
}

10 个答案:

答案 0 :(得分:13)

您应该写入已分配的块。如果你只是要求内存,linux可能只是分发内存预留,但在访问内存之前不会分配任何内容。

int main()
{
        while(1)
        {
                void *m = malloc(1024*1024);
                memset(m,0,1024*1024);
        }
        return 0;
}

你真的只需要在每个页面上写1个字节(通常在x86上为4096个字节)。

答案 1 :(得分:10)

Linux“over commit”内存。这意味着物理内存仅在进程首次尝试访问时为进程提供,时首次执行malloc。要禁用此行为,请执行以下操作(以root用户身份):

echo 2 > /proc/sys/vm/overcommit_memory

然后尝试运行您的程序。

答案 2 :(得分:3)

默认情况下,Linux使用我称之为“机会分配”的东西。这是基于观察到许多真实程序分配的内存比实际使用的内存多。 Linux使用它来将更多内容放入内存:它只在使用时分配一个内存页面,而不是在使用malloc(或mmap或sbrk)分配时。

如果你在循环中做了类似的事情,你可能会取得更大的成功:

memset(malloc(1024*1024L), 'w', 1024*1024L);

答案 3 :(得分:3)

一个鲜为人知的事实(尽管已有详细记录) - 您可以(以root身份)阻止OOM杀手将您的流程(或任何其他流程)声称为其受害者之一。这是一个直接来自我的编辑器的片段,我(基于配置数据)锁定所有已分配的内存以避免被分页和(可选)告诉OOM杀手不要打扰我:

static int set_priority(nex_payload_t *p)
{
    struct sched_param sched;
    int maxpri, minpri;
    FILE *fp;
    int no_oom = -17;

    if (p->cfg.lock_memory)
        mlockall(MCL_CURRENT | MCL_FUTURE);

    if (p->cfg.prevent_oom) {
        fp = fopen("/proc/self/oom_adj", "w");
        if (fp) {
            /* Don't OOM me, Bro! */
            fprintf(fp, "%d", no_oom);
            fclose(fp);
        }
    }

我没有显示我正在使用调度程序参数做什么,因为它与问题无关。

这将阻止OOM杀手在它有机会产生(在这种情况下)所需效果之前获得你的过程。实际上,您还会将大多数其他进程强制转移到磁盘上。

所以,简而言之,要快速看烟花......

  1. 告诉OOM杀手不要打扰你
  2. 锁定你的记忆
  3. 在永不停止的循环中分配和初始化(清零)块,或直到malloc()失败
  4. 请务必同时查看ulimit,并以root身份运行测试。

    我展示的代码是守护进程的一部分,它不会失败,它以非常高的权重运行(有选择地使用RR或FIFO调度程序)并且不能(永远)被分页。

答案 4 :(得分:3)

在我的机器中,使用适当的gb值,以下代码使用了100%的内存,甚至将内存放入交换中。 您可以看到每个页面只需要写一个字节:memset(m, 0, 1);, 如果您将页面大小:#define PAGE_SZ (1<<12)更改为更大的页面大小:#define PAGE_SZ (1<<13),那么您将不会写入您分配的所有页面,因此您可以在顶部看到程序的内存消耗沮丧。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define PAGE_SZ (1<<12)

int main() {
    int i;
    int gb = 2; // memory to consume in GB

    for (i = 0; i < ((unsigned long)gb<<30)/PAGE_SZ ; ++i) {
        void *m = malloc(PAGE_SZ);
        if (!m)
            break;
        memset(m, 0, 1);
    }
    printf("allocated %lu MB\n", ((unsigned long)i*PAGE_SZ)>>20);
    getchar();
    return 0;
}

答案 5 :(得分:2)

看一下这个程序。 当没有足够的内存时,malloc开始返回0

#include <stdlib.h>
#include <stdio.h>

int main()
{
  while(1)
  {
    printf("malloc %d\n", (int)malloc(1024*1024));
  }
  return 0;
}

答案 6 :(得分:1)

在32位Linux系统上,单个进程在其地址空间中可以分配的最大值大约为3Gb。

这意味着你不可能只用一个进程耗尽内存。

另一方面,在64位计算机上,您可以根据需要进行分配。

正如其他人所说,还需要初始化内存,否则它实际上不会占用页面。

如果操作系统没有剩余虚拟内存,或者进程超出地址空间(或者不足以满足请求的分配),则

malloc将开始发出错误。

正如其他人所指出的那样,Linux的虚拟机过度使用也会影响它的确切时间和发生的情况。

答案 7 :(得分:0)

我曾厌倦过这样做过。得到这个耗尽所有内存,需要强制重新启动才能让它再次运行。

#include <stdlib.h>
#include <unistd.h>

int main(int argc, char** argv)
{
    while(1)
    {
        malloc(1024 * 4);
        fork();
    }
}

答案 8 :(得分:0)

如果您只需要强调系统,那么就会有stress工具,它可以完全满足您的需求。它可以作为大多数发行版的包装。

答案 9 :(得分:-1)

我刚刚执行了@John La Rooy的片段:

#include <stdlib.h>
#include <stdio.h>

int main()
{
  while(1)
  {
    printf("malloc %d\n", (int)malloc(1024*1024));
  }
  return 0;
}

但它很快耗尽了我的记忆并导致系统被绞死,所以我不得不重新启动它。

所以我建议你改变一些代码。

例如: 在我的ubuntu 16.04 LTS上,下面的代码大约需要1.5 GB ram,执行后物理内存消耗从1.8 GB增加到3.3 GB,并在完成执行后回落到1.8GiB。虽然看起来我在代码中分配了300GiB ram。

#include <stdlib.h>
#include <stdio.h>

int main()
{
  while(int i<300000)
  {
    printf("malloc %p\n", malloc(1024*1024));
    i += 1;
  }
  return 0;
}

当索引 i 小于100000(即分配小于100 GB)时,物理或虚拟内存只是略微使用(小于100MB),我不知道为什么,可能与虚拟内存有关。

有趣的是,当物理内存开始缩小时,地址malloc()肯定会返回更改,请参阅下面的图片链接。

我使用了malloc()和calloc(),似乎它们在占用物理内存方面表现得相似。

memory address number changes from 48 bits to 28 bits when physical memory begins shrinking