内存分配如何在极端情况下工作?

我很困惑内存分配(malloc / calloc)如何在linux / c中工作。 假设,我有一台拥有16GB RAM的机器,我以root身份运行一个程序。 它是64位机器,因此所有16GB都可以作为一个单独的网段寻址。 我可以通过一次malloc调用来分配所有这些(减少操作系统的数量)吗? 有很多malloc调用?

这与“堆内存”和“虚拟内存”有什么关系? 如果我分配一个小内存块,它发生在堆内存中,那么我调整(放大)这个块,当我接近堆栈区时会发生什么?

如果我想(几乎)所有RAM都分配给我的单个进程,即使认为它以root身份运行,我是否还必须摆弄selimlimit RLIMIT_AS?


一个64位的进程可以分配所有的内存。 它甚至不需要是root用户,除非系统为非root用户定义了ulimit设置。 尝试ulimit -v以查看是否设置了限制。

在Linux默认设置下,进程可以请求几乎任意数量的内存,并且将被授予。 内存将按照使用情况进行实际分配,它将根据需要来自物理RAM或磁盘交换。

内存分配调整大小通常在C库中进行,方法是分配新的较大的大小并将旧数据复制到新分配中。 这通常不是通过扩大现有分配来完成的。 内存分配选择为不与其他分配(如程序堆栈)冲突。


在虚拟内存OS(如Linux)上,malloc()不分配内存。 它分配地址空间例如,编译并运行以下片段,并(在另一个终端中)运行top

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

int main(void) {
  char *cp;
  cp = malloc( 16ULL * 1024 *1024 *1024);
  if (cp) pause();
  return 0;
}

在我的电脑上,TOP显示:

PID    USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND            
29026 plasser    20   0 16.0g  324  248 S    0  0.0   0:00.00 a.out 

这意味着:a.out具有16GB的虚拟大小,并且只使用324(bytes?KB?)常驻内存(可能只是二进制文件)

发生了什么事?

  • malloc()调用已经要求操作系统扩展地址空间 ,增加16 GB
  • 操作系统已经完成了这个请求,并为它建立了页面表等等。
  • 这些页表没有连接到它们的物理内存(可能),除了表格本身
  • 一旦程序开始引用这个地址空间,页面将被连接(操作系统将会使他们错误)
  • (这些页面可能会从/ dev / zero中删除,但这只是一个细节)
  • 但是,在程序确实引用地址时,内存将不得不由操作系统分配并附加到进程中。 (它会出现在RES领域,相信我)
  • 在某些时候,一旦操作系统认为它已经很长时间没有被使用,连接的内存也可能被分离。 它将被添加到一个可用内存池或/和用于其他目的。 在这种情况下,其内容可能会推送到后备存储(磁盘)
  • `


    malloc()可以通过扩展堆或通过mmap()来分配足够大的内存块来分配内存。 他们使用哪一个取决于您请求的大小以及几个mallopt()选项。

    如果它使用通常位于虚拟内存区域起始处的“真正的”堆部分,则它可以长到它碰到下一个分配的内存块的位置,该内存块离开始处很远。

    如果它使用mmap() ,则取决于是否存在可用的连续地址空间。

    /proc/<PID>/maps是查找进程的地址空间情况的良好查询点。

    我刚刚使用Python和ctypes测试了我的64位服务器:

    import ctypes
    import ctypes.util
    m=ctypes.CDLL(ctypes.util.find_library("c")).malloc
    m.argtypes=(ctypes.c_uint64,)
    m.restype = ctypes.c_uint64
    

    现在我有m ,它用作对libc的malloc()函数的调用。

    现在我可以做

    >>> hex(m(2700000000))
    '0x7f1345e3b010L'
    >>> hex(m(2700000000))
    '0x7f12a4f4f010L'
    >>> hex(m(2700000000))
    '0x7f1204063010L'
    >>> hex(m(2700000000))
    '0x7f1163177010L'
    >>> hex(m(2700000000))
    '0x7f10c228b010L'
    >>> hex(m(2700000000))
    '0x7f102139f010L'
    >>> hex(m(2700000000))
    '0x7f0f804b3010L'
    

    但由于我无法做到的任何原因

    >>> hex(m(2900000000))
    '0x0L'
    

    因为它返回0和。 一个NULL指针。

    现在在做

    print open("/proc/self/maps").read()
    

    向我显示所述文件的行; 在某处

    7f0ed8000000-7f0ed8021000 rw-p 00000000 00:00 0 
    7f0ed8021000-7f0edc000000 ---p 00000000 00:00 0 
    7f0edf5c7000-7f13e6d27000 rw-p 00000000 00:00 0 
    

    我得到了我的分配。

    但是,如果我这样做

    >>> hex(m(1))
    '0x1f07320L'
    >>> hex(m(1))
    '0x1f0c0e0L'
    >>> hex(m(1))
    '0x1f02d50L'
    >>> hex(m(1))
    '0x1f02d70L'
    >>> hex(m(1))
    '0x1ef94f0L'
    >>> hex(m(1))
    '0x1eb7b20L'
    >>> hex(m(1))
    '0x1efb700L'
    >>> hex(m(270))
    '0x1f162a0L'
    >>> hex(m(270))
    '0x1f163c0L'
    >>> hex(m(270))
    '0x1f164e0L'
    >>> hex(m(270))
    '0x1f16600L'
    

    内存地址来自

    >>> print open("/proc/self/maps").read()
    [...]
    01d2e000-01f2b000 rw-p 00000000 00:00 0                                  [heap]
    [...]
    

    指定的堆。

    请注意,尽管我可以分配此内存,但使用它们都会造成伤害,因为我的进程可能会被着名的OOM杀手杀死。

    链接地址: http://www.djcxy.com/p/82715.html

    上一篇: how memory allocation works at extremes?

    下一篇: C Memory Management in Embedded Systems