过度使用记账(Overcommit Accounting)

overcommit handing modes

Linux内核支持以下 overcommit 处理模式:

  • 0 : 启发式 overcommit

启发式过度分配 拒绝明显的地址空间过度使用,用于典型系统(默认配置)。这种处理模式可以确保严重的疯狂分配(seriously wild allocation)失败,同时允许(适当) overcommit 以减少swap空间使用。这个模式也允许 root 用户分配更多的内存。

  • 1 : 始终 overcommit

始终过度分配 适合一些科学应用。典型的案例是使用稀疏矩阵(sparse arrays)的代码,并且仅依赖完全由 零页面 (zero pages)组成的虚拟内存

  • 2 : 禁止 overcommit

禁止过度分配 设置下,系统的总地址空间提交(total address space commit)不允许超过 swap + (物理内存*overcommit_ratio) 的可配置数量( overcommit_ratio 默认是 50% )。根据内存使用量,大多数情况下进程在访问页面时不会被终止,但是会在恰当的时候收到内存分配错误

检查和设置 overcommit 处理模式

sysctl 检查 vm.overcommit_memory 设置值:

sysctl 检查 vm.overcommit_memory 设置值
sysctl vm.overcommit_memory

通常情况下,该值是 0 (启发式过度分配):

vm.overcommit_memory 设置值通常为0
vm.overcommit_memory = 0

直接检查 /proc/sys 下的配置也可以查看该配置:

检查procfs中 vm.overcommit_memory 设置
cat /proc/sys/vm/overcommit_memory

配合 overcommit 配置值 2 的两个参数

vm.overcommit_memory 设置为 2 (也就是禁止过度分配)时,此时有两个配套参数(仅在 vm.overcommit_memory = 2 时生效):

  • vm.overcommit_ratio 过度分配百分比,也就是 swap + RAM 的百分比允许过度分配

  • vm.overcommit_kbytes 过度分配绝对值

上述两个配套参数入口也位于 /proc/sys/vm 下:

# ls /proc/sys/vm/overcommit*
/proc/sys/vm/overcommit_kbytes  /proc/sys/vm/overcommit_memory  /proc/sys/vm/overcommit_ratio

这两个值默认不生效( 因为系统默认 vm.overcommit_memory = 0 ):

# sysctl vm.overcommit_kbytes
vm.overcommit_kbytes = 0

# sysctl vm.overcommit_ratio
vm.overcommit_ratio = 50

当前 overcomit

当前系统的过度使用限制(overcommit limit)和提交量(ammount commmited)可以通过 /proc/meminfoCommitLimitCommitted_AS 查看

案例:

  • 检查Linux系统内存分配:

检查 /proc/meminfo
cat /proc/meminfo

输出信息:

cat /proc/meminfo 输出信息
MemTotal:       197928076 kB
MemFree:        144126316 kB
MemAvailable:   144382540 kB
Buffers:          247316 kB
Cached:          1113060 kB
SwapCached:            0 kB
Active:         15591136 kB
Inactive:       36330216 kB
Active(anon):   14844596 kB
Inactive(anon): 35731580 kB
Active(file):     746540 kB
Inactive(file):   598636 kB
Unevictable:       31172 kB
Mlocked:           28100 kB
SwapTotal:             0 kB
SwapFree:              0 kB
Dirty:               276 kB
Writeback:             0 kB
AnonPages:      50592164 kB
Mapped:           192984 kB
Shmem:              6128 kB
KReclaimable:     157340 kB
Slab:            1106652 kB
SReclaimable:     157340 kB
SUnreclaim:       949312 kB
KernelStack:       12784 kB
PageTables:       105972 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:    98964036 kB
Committed_AS:   52750596 kB
VmallocTotal:   34359738367 kB
VmallocUsed:      310252 kB
VmallocChunk:          0 kB
Percpu:            48384 kB
HardwareCorrupted:     0 kB
AnonHugePages:  50331648 kB
ShmemHugePages:        0 kB
ShmemPmdMapped:        0 kB
FileHugePages:         0 kB
FilePmdMapped:         0 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
Hugetlb:               0 kB
DirectMap4k:      578044 kB
DirectMap2M:    10823680 kB
DirectMap1G:    191889408 kB

可以看到 MemTotal 表示主机实际安装内存大小(192G); 内存过度使用当前限制大约是 94.4GB ,而当前过度分配提交量是 50.3GB

验证

调整 vm.overcommit_memory
# cat /proc/meminfo | grep 'MemTotal\|SwapTotal'
MemTotal:       197928076 kB
SwapTotal:             0 kB
# cat /proc/sys/vm/overcommit_memory
0

调整为禁止overcommit策略
# echo 2 > /proc/sys/vm/overcommit_memory
# sysctl vm.overcommit_memory
vm.overcommit_memory = 2
此时 overcommit_ratio 参数生效: 50%
# sysctl vm.overcommit_ratio
vm.overcommit_ratio = 50
# cat /proc/meminfo | grep 'CommmitLimit\|Committed_AS'
Committed_AS:   52758336 kB
# cat /proc/meminfo | grep 'CommitLimit\|Committed_AS'
CommitLimit:    98964036 kB
Committed_AS:   52758336 kB

调整 overcommit_ratio 参数到 200%,可以看到 CommitLimit 一下子从 98964036 kB 改变到 395856152 kB
# sysctl vm.overcommit_ratio=200
vm.overcommit_ratio = 200
# sysctl vm.overcommit_ratio
vm.overcommit_ratio = 200
# cat /proc/meminfo | grep 'CommitLimit\|Committed_AS'
CommitLimit:    395856152 kB
Committed_AS:   52758336 kB

恢复默认的 "启发型overcommit模式"
# echo 0 > /proc/sys/vm/overcommit_memory
# cat /proc/meminfo | grep 'CommitLimit\|Committed_AS'
CommitLimit:    395856152 kB
Committed_AS:   52758336 kB

在启发式overcommit模式,之前在禁止overcommit模式下配置的 overcommit_ratio 还是200,此时不会自动收缩 CommitLimit
# sysctl vm.overcommit_ratio=50
vm.overcommit_ratio = 50
# cat /proc/meminfo | grep 'CommitLimit\|Committed_AS'
CommitLimit:    98964036 kB
Committed_AS:   52758336 kB

参考