为什么不这样吃内存真的吃内存? [英] Why doesn't this memory eater really eat memory?

查看:107
本文介绍了为什么不这样吃内存真的吃内存?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建一个程序,将模拟的Unix服务器上的外存储器(OOM)的情况。我创造了这个超级简单的内存食:

I want to create a program that will simulate an out-of-memory (OOM) situation on a Unix server. I created this super-simple memory eater:

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

unsigned long long memory_to_eat = 1024 * 50000;
size_t eaten_memory = 0;
void *memory = NULL;

int eat_kilobyte()
{
    memory = realloc(memory, (eaten_memory * 1024) + 1024);
    if (memory == NULL)
    {
        // realloc failed here - we probably can't allocate more memory for whatever reason
        return 1;
    }
    else
    {
        eaten_memory++;
        return 0;
    }
}

int main(int argc, char **argv)
{
    printf("I will try to eat %i kb of ram\n", memory_to_eat);
    int megabyte = 0;
    while (memory_to_eat > 0)
    {
        memory_to_eat--;
        if (eat_kilobyte())
        {
            printf("Failed to allocate more memory! Stucked at %i kb :(\n", eaten_memory);
            return 200;
        }
        if (megabyte++ >= 1024)
        {
            printf("Eaten 1 MB of ram\n");
            megabyte = 0;
        }
    }
    printf("Successfully eaten requested memory!\n");
    free(memory);
    return 0;
}

它吃在 memory_to_eat 定义尽可能多的内存现在正是50 NBSP; GB的RAM。它通过1 NBSP分配内存; MB和版画究竟在何处出现故障的时间分配更多,所以我知道它设法吃的最大值

It eats as much memory as defined in memory_to_eat which now is exactly 50 GB of RAM. It allocates memory by 1 MB and prints exactly the point where it fails to allocate more, so that I know which maximum value it managed to eat.

的问题是,它的工作原理。即使在1&NBSP系统; GB的物理内存

The problem is that it works. Even on a system with 1 GB of physical memory.

当我检查前我看到进程吃50 NBSP; GB的虚拟内存,只有不到1&NBSP;驻留内存的MB。有没有一种方法来创建一个存储吃了确实消耗了吗?

When I check top I see that the process eats 50 GB of virtual memory and only less than 1 MB of resident memory. Is there a way to create a memory eater that really does consume it?

系统规格:启用Linux内核3.16( Debian的)最有可能与过量使用(不知道如何检查出来)没有交换和虚拟化。

System specifications: Linux kernel 3.16 (Debian) most likely with overcommit enabled (not sure how to check it out) with no swap and virtualized.

推荐答案

在你的的malloc()实施从系统内核请求的内存(通过 SBRK()的mmap()系统调用),内核只会让你所要求的存储笔记,并在那里是要放置在您的地址空间内。的实际上它并不这些页面映射尚未

When your malloc() implementation requests memory from the system kernel (via an sbrk() or mmap() system call), the kernel only makes a note that you have requested the memory and where it is to be placed within your address space. It does not actually map those pages yet.

在该进程随后在新区域内访问内存,硬件识别段故障,并提醒内核的条件。然后在内核中查找页在其自己的数据结构,并且认为,你应该有一个零页存​​在,因此它在一个零页映射(可能第一逐出从页缓存页)和从中断返回。过程不知道,任何发生的这一切,该内核操作完全透明的(除了短暂的延迟,而内核做的工作)。

When the process subsequently accesses memory within the new region, the hardware recognizes a segmentation fault and alerts the kernel to the condition. The kernel then looks up the page in its own data structures, and finds that you should have a zero page there, so it maps in a zero page (possibly first evicting a page from page-cache) and returns from the interrupt. Your process does not realize that any of this happened, the kernels operation is perfectly transparent (except for the short delay while the kernel does its work).

这个优化使得系统调用很快恢复,而且,最重要的是,它避免了任何资源致力于流程映射时作出。这允许进程保留相当大的缓冲区,他们从来没有在正常情况下的需要,而不必担心吞噬了太多的记忆。

This optimization allows the system call to return very quickly, and, most importantly, it avoids any resources to be committed to your process when the mapping is made. This allows processes to reserve rather large buffers that they never need under normal circumstances, without fear of gobbling up too much memory.

所以,如果你想程序的存储器吃,你绝对要真正做到与你分配内存的东西。对于这一点,你只需要一行添加到您的code:

So, if you want to program a memory eater, you absolutely have to actually do something with the memory you allocate. For this, you only need to add a single line to your code:

int eat_kilobyte()
{
    if (memory == NULL)
        memory = malloc(1024);
    else
        memory = realloc(memory, (eaten_memory * 1024) + 1024);
    if (memory == NULL)
    {
        return 1;
    }
    else
    {
        //Force the kernel to map the containing memory page.
        ((char*)memory)[1024*eaten_memory] = 42;

        eaten_memory++;
        return 0;
    }
}

请注意,这是完全足以写入每个页中的单个字节(它包含于X86的4096个字节)。这是因为从内核所有内存分配给一个过程是在存储器页粒度,这一点,反过来做,因为不允许寻呼在较小粒度的硬件,

Note that it is perfectly sufficient to write to a single byte within each page (which contains 4096 bytes on X86). That's because all memory allocation from the kernel to a process is done at memory page granularity, which is, in turn, because of the hardware that does not allow paging at smaller granularities.

这篇关于为什么不这样吃内存真的吃内存?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆