如何在不过度使用的情况下在 Linux 上分配内存,以便 mallocNULL
在没有可用内存并且进程在访问时不会随机崩溃时实际返回?
我对 malloc 工作原理的理解:
- 如果有空闲内存,分配器会检查空闲列表。如果是,则分配内存。
- 如果否,则从内核分配新页面。这将是可能发生过度使用的地方。然后返回新的内存。
因此,如果有一种方法可以从内核获取由物理内存立即支持的内存,分配器可以使用它而不是获取过度使用的页面,并NULL
在内核拒绝提供更多内存时返回。
有没有办法做到这一点?
更新:
我知道这不能完全保护进程免受 OOM 杀手的影响,因为如果它的分数不好,它仍然会在内存不足的情况下被杀死,但这不是我担心的。
更新 2:
Nominal Animal 的评论给了我以下使用的想法mlock
:
void *malloc_without_overcommit(size_t size) {
void *pointer = malloc(size);
if (pointer == NULL) {
return NULL;
}
if (mlock(pointer, size) != 0) {
free(pointer);
return NULL;
}
return pointer;
}
但这可能由于所有系统调用而相当慢,因此这可能应该在分配器实现级别完成。而且它还阻止了使用交换。
更新 3:
遵循 John Bollingers 的评论的新想法:
- 检查是否有足够的内存可用。据我了解,这必须
/proc/meminfo
在MemFree
andSwapFree
值中进行检查。 - 仅当有足够的可用空间(加上额外的安全余量)时,才分配内存。
- 找出
getpagesize
每个页面大小的页面大小并将一个字节写入内存,以便它得到物理内存(RAM或交换)的支持。
我还更仔细地查看了mmap(2)并发现以下内容:
MAP_NORESERVE
不要为此映射保留交换空间。保留交换空间时,可以保证可以修改映射。如果没有保留交换空间,如果没有可用的物理内存,可能会在写入时获得 SIGSEGV。另请参见 proc(5) 中对文件 /proc/sys/vm/overcommit_memory 的讨论。在 2.6 之前的内核中,此标志仅对私有可写有效
这是否意味着映射~MAP_NORESERVE
将完全保护进程免受 OOM 杀手的影响?如果是这样,这将是一个完美的解决方案,只要有一个malloc
可以直接在mmap
. (也许是jemalloc?)
更新 4:
我目前的理解是,这~MAP_NORESERVE
不会防止 OOM 杀手,但至少可以防止第一次写入内存时出现段错误。