我很困惑如何内存分配(malloc / calloc)在linux / c工程。 假设,我有一台16GB RAM的机器,并以root身份运行一个程序。 这是64位的机器,所以所有的16GB可以作为一个单一的网段。 我可以用一个malloc调用来分配所有这些(less于OS的数量)吗? 有很多malloc调用?
这与“堆内存”和“虚拟内存”有什么关系? 如果我分配一个小内存块,它发生在堆内存,然后我调整(放大)这个块,当我接近堆栈区时会发生什么?
如果我想(几乎)所有的内存分配给我的单个进程,甚至认为它是以root身份运行的,我是否必须摆弄selimlimit RLIMIT_AS?
一个64位的进程可以分配所有的内存。 它甚至不需要是root,除非系统为非root用户定义了一个ulimit
设置。 尝试ulimit -v
来查看是否设置了限制。
在Linux的默认设置下,一个进程可以要求几乎任意数量的内存,它将被授予。 内存将按照使用情况进行实际分配,并根据需要从物理内存或磁盘交换中进行分配。
内存分配调整大小通常在C库中完成,方法是分配新的更大的大小,并将旧数据复制到新分配中。 这通常不是通过扩大现有分配来完成的。 内存分配选择为不与其他分配(如程序堆栈)冲突。
在虚拟内存操作系统(如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?)常驻内存(可能只是二进制文件)
发生什么事了?
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杀手杀害。