/proc/sys/vm/overcommit_memory
控制 Linux 上的最大值
例如,在 Ubuntu 19.04 上,我们可以很容易地看到它malloc
是mmap(MAP_ANONYMOUS
使用strace
.
然后man proc
再描述如何/proc/sys/vm/overcommit_memory
控制最大分配:
该文件包含内核虚拟内存记帐模式。值为:
- 0:启发式过度使用(这是默认值)
- 1:总是过度使用,从不检查
- 2:总是检查,从不过度使用
在模式 0 中,不检查带有 MAP_NORESERVE 的 mmap(2) 调用,并且默认检查非常弱,导致进程“OOM-killed”的风险。
在模式 1 中,内核假装总是有足够的内存,直到内存实际耗尽。这种模式的一个用例是使用大型稀疏数组的科学计算应用程序。在 2.6.0 之前的 Linux 内核版本中,任何非零值都意味着模式 1。
在模式 2(自 Linux 2.6 起可用)中,可分配的总虚拟地址空间(/proc/meminfo 中的 CommitLimit)计算为
CommitLimit = (total_RAM - total_huge_TLB) * overcommit_ratio / 100 + total_swap
在哪里:
- total_RAM 是系统上的 RAM 总量;
- total_huge_TLB 是为大页面预留的内存量;
- overcommit_ratio 是 /proc/sys/vm/overcommit_ratio 中的值;和
- total_swap 是交换空间的数量。
例如,在具有 16GB 物理 RAM、16GB 交换空间、没有专用于大页面的空间以及 overcommit_ratio 为 50 的系统上,此公式得出的 CommitLimit 为 24GB。
从 Linux 3.14 开始,如果 /proc/sys/vm/overcommit_kbytes 中的值不为零,则 CommitLimit 的计算方式为:
CommitLimit = overcommit_kbytes + total_swap
另请参见 /proc/sys/vm/admiin_reserve_kbytes 和 /proc/sys/vm/user_reserve_kbytes 的描述。
5.2.1 内核树中的Documentation/vm/overcommit-accounting.rst也提供了一些信息,虽然有点少:
Linux内核支持以下overcommit处理模式
0
启发式过度使用处理。明显的地址空间过度使用被拒绝。用于典型系统。它确保严重的疯狂分配失败,同时允许过度使用以减少交换使用。在这种模式下,root 可以分配稍微多一点的内存。这是默认设置。
1
总是过度使用。适用于一些科学应用。经典示例是使用稀疏数组的代码,并且仅依赖于几乎完全由零页组成的虚拟内存。
2
不要过度使用。系统的总地址空间提交不允许超过交换 + 物理 RAM 的可配置数量(默认为 50%)。根据您使用的数量,在大多数情况下,这意味着进程在访问页面时不会被杀死,但会在适当的时候收到内存分配错误。
对于希望保证其内存分配将来可用而不必初始化每个页面的应用程序很有用。
最小的实验
我们可以很容易地看到允许的最大值:
主程序
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char **argv) {
char *chars;
size_t nbytes;
/* Decide how many ints to allocate. */
if (argc < 2) {
nbytes = 2;
} else {
nbytes = strtoull(argv[1], NULL, 0);
}
/* Allocate the bytes. */
chars = mmap(
NULL,
nbytes,
PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS,
-1,
0
);
/* This can happen for example if we ask for too much memory. */
if (chars == MAP_FAILED) {
perror("mmap");
exit(EXIT_FAILURE);
}
/* Free the allocated memory. */
munmap(chars, nbytes);
return EXIT_SUCCESS;
}
GitHub 上游.
编译运行分配1GiB和1TiB:
gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
./main.out 0x40000000
./main.out 0x10000000000
然后我们可以使用分配值来查看系统允许什么。
我找不到0
(默认)的精确文档,但是在我的 32GiB RAM 机器上它不允许 1TiB 分配:
mmap: Cannot allocate memory
但是,如果我启用无限过量使用:
echo 1 | sudo tee /proc/sys/vm/overcommit_memory
然后 1TiB 分配工作正常。
模式2
有据可查,但我懒得进行精确计算来验证它。但我只想指出,在实践中,我们可以分配:
overcommit_ratio / 100
总内存,默认overcommit_ratio
情况50
下,所以我们可以分配大约一半的总内存。
VSZ vs RSS 和内存不足的杀手
到目前为止,我们刚刚分配了虚拟内存。
但是,当然,在某些时候,如果您使用了足够多的这些页面,Linux 将不得不开始杀死一些进程。
我已经详细说明了:Linux内存管理中的RSS和VSZ是什么