Linux中的malloc() - "无法保证内存确实可用"?

Hul*_*000 5 c linux memory-management

我正在制作一个游戏,将世界划分为描述世界的数据块.我将块保存在动态分配的数组中,因此我必须malloc()在初始化世界的数据结构时使用.

阅读malloc()手册页,有一个注释如下:

默认情况下,Linux遵循乐观的内存分配策略.这意味着当malloc()返回非NULL时,无法保证内存确实可用.如果事实证明系统内存不足,那么一个或多个进程将被OOM杀手杀死.欲了解更多信息,请参阅的说明 的/ proc/sys目录/ VM/overcommit_memory的/ proc/sys目录/ VM/oom_adjproc(5),和Linux内核源文件 文档/ VM /过载会计.

如果Linux设置为使用乐观内存分配,那么这是否意味着它并不总是返回我在调用中请求的全部内存量malloc()

我读到通过修改内核来禁用乐观内存分配,但我不想这样做.

那么有没有办法检查程序是否已分配所请求的金额?

R..*_*R.. 6

从应用程序的角度来看,这不是您需要处理的事情.不希望被"OOM杀手"杀死的随机进程的用户将通过自身禁用过度使用

echo "2" > /proc/sys/vm/overcommit_memory
Run Code Online (Sandbox Code Playgroud)

这是他们的选择,而不是你的选择.

但从另一个角度来看,这并不重要.典型的"推荐"交换量是如此荒谬,以至于没有合理数量的malloc物理存储无法支持它.但是,您可以轻松分配这么多(即使强制MAP_POPULATE或手动触摸它),以保持系统颠簸交换数小时/天/周.没有规范的方法要求系统通知您,如果您想要的内存量将使系统交换陷入困境,则会出错.

整个情况一团糟,但作为应用程序开发人员,您在修复中的角色只是malloc正确使用并检查null返回值.其余的责任在于发行版和内核维护者.

  • @BasileStarynkevitch:是否每个程序都需要对此进行记录?是否有必要记录每个可能影响程序的已知Linux错误/功能缺陷?我同意,如果您在实践中发现问题,则可能需要记录以下内容:“该程序需要X内存。如果在运行该程序或其他程序时遇到严重的交换或崩溃,则需要更多的内存。您可能考虑禁用过量使用(请参阅xxxx文档),以便诊断出这种情况,而不是触发OOM杀手。” 但是否则我就别管它了。 (3认同)

Ant*_*ala 3

您可以直接malloc通过 分配必要的内存mmapMAP_POPULATE这会建议内核立即映射页面。

#include <sys/mman.h>

// allocate length bytes and prefault the memory so 
// that it surely is mapped
void *block = mmap(NULL, length, PROT_READ|PROT_WRITE, 
       MAP_PRIVATE|MAP_ANONYMOUS|MAP_POPULATE,
       -1, 0);

// free the block allocated previously
// note, you need to know the size
munmap(block, length);
Run Code Online (Sandbox Code Playgroud)

但更好的选择是,通常世界会保存到文件中,因此您可以mmap直接从文件中获取内容:

int fd = open('world.bin', 'r+');
void *block = mmap(NULL, <filesize>, PROT_READ|PROT_WRITE,
    MAP_SHARED, fd, 0);
Run Code Online (Sandbox Code Playgroud)

文件world.bin被映射到从地址开始的内存中block;对内存的所有更改也会透明地写入文件 - 无需担心是否有足够的 RAM,因为 Linux 会自动映射页面进出。


请注意,除非您定义了某个功能测试宏,否则不会定义其中一些标志:

_BSD_SOURCE仅当定义了或 时才定义某些标志常量_SVID_SOURCE。(要求_GNU_SOURCE也足够了,并且专门要求该宏会更符合逻辑,因为这些标志都是 Linux 特定的。)相关标志是: MAP_32BIT, MAP_ANONYMOUS (和同义词 MAP_ANON), MAP_DENYWRITE, MAP_EXECUTABLE, MAP_FILE, MAP_GROWSDOWN, MAP_HUGETLB, MAP_LOCKED, MAP_NONBLOCK, MAP_NORESERVE, MAP_POPULATE, 和MAP_STACK