限制内存使用量
今天和小伙伴分享一些Linux 内存限制相关知识,主要涉及如何配置以及什么情况下需要配置,我们知道内存属于不可压缩资源,当没有那么多的物理内存可以映射,进程都无法启动,所以为了公平,亦或是考虑部分进程 Qos 级别,一般情况下会对进程进行内存限制,即保证机器上的多个进程不会因为业务对基础资源的弹性要求,相互影响,比如类似FTP进程的内存泄露问题影响到核心业务服务触发 OOM ,甚至直接被OOM killer 掉。
简单介绍,关于内存资源限制在 Linux 中,一般按照限制手段来划分的话,分为
内核参数(包括启动配置)限制: 临时修改交换分区频率sysctl -w vm.swappiness=10, 启动引导配置大页参数grubby --update-kernel=ALL --args="hugepagesz=1G hugepages=10"。Cgroup(包括systemd)限制: 通过 Cgroup 的 memory 子系统限制 /sys/fs/cgroup/memory/myapp/memory.limit_in_bytes,MemoryMax=1G。ulimit 限制: ulimit -v 2097152。
三种方式,按照限制类型划分,一般分为:
系统内存限制: 比如修改内核参数sysctl -w vm.overcommit_memory=2 禁止过度分配虚拟内存。进程内存限制: Systemd 单元限制进程物理内存不超过 1G MemoryMax=1G。用户会话内存限制: echo "john hard as 2097152" >> /etc/security/limits.conf 限制用户 john 的进程最大虚拟内存(地址空间)为 2 GB。
如果按照具体的内存种类划分,可以分为:
物理、虚拟内存限制: 硬限制物理内存大小 memory.limit_in_bytes, 会话级别虚拟内存限制 ulimit -v。数据段,数据栈限制: ulimit -d 262144 设置数据段的最大值。数据缓存区: 释放内存缓存区设置 vm.drop_caches,网络IO 相关缓存区配置 net.ipv4.tcp_rmem。大页,脏页相关内存页限制:大页大小 vm.nr_hugepages。
Cgroup
Cgroup(Control Groups)最早由 google 开发,后来内置到了 Linux 内核中,是Linux kernel(Linux内核)的一项功能,目前是很多虚拟化容器技术的底层核心技术。
在一个系统中运行的层级制进程组,Cgroup 可对其进行资源分配(如CPU时间、系统内存、网络带宽或者这些资源的组合)。
通过使用cgroup ,系统管理员在分配、排序、拒绝、管理和监控系统资源等方面,可以进行精细化控制。硬件资源可以在应用程序和用户间智能分配,从而增加整体效率。
Cgroup可对进程进行层级式分组并标记,并对其可用资源进行限制。通过将cgroup层级系统与systemd单位树捆绑, Linux 可以把资源管理设置从进程级别移至应用程序级别。
可以使用systemctl指令,或者通过修改systemd单位文件来管理系统资源。
为了控制重要的内核资源,systemd 会自动挂载/sys/fs/cgroup 目录实现 cgroup 分层架构,Linux 内核的资源管理器,也叫 CGroup 子系统,代表某一种单一资源(如 CPU 时间或内存等。
Linux 内核提供了一系列资源管理器,由 systemd 自动挂载。如果需要查看已经挂载的资源管理器列表,可以参考/proc/cgroups。
内存子系统位于其中:
memory: 对 cgroup 中的任务使用内存量进行限制,并且自动生成任务占用内存资源的报告。
在安装了 kernel-doc 软件包后,可以在/usr/share/doc/kernel-doc-<version>/Documentation/cgroup 目录下找相关管理器的说明文档,从而配置合适的资源限制。
复制
┌──[root@liruilongs.github.io]-[/usr/share/doc/kernel-doc-4.18.0/Documentation/cgroup-v1]
└─$ls
00-INDEX cgroups.txt cpusets.txt freezer-subsystem.txt memcg_test.txt net_cls.txt pids.txt
blkio-controller.txt cpuacct.txt devices.txt hugetlb.txt memory.txt net_prio.txt rdma.txt
┌──[root@liruilongs.github.io]-[/usr/share/doc/kernel-doc-4.18.0/Documentation/cgroup-v1]
└─$ll
total 184
。。。。。。。。。。。。。。。。
-r--r--r--. 1 root root 8480 Mar 27 2020 memcg_test.txt
-r--r--r--. 1 root root 37743 Mar 27 2020 memory.txt
................1.2.3.4.5.6.7.8.9.10.11.
简单的信息可以通过索引文件的了解。
复制
┌──[root@liruilongs.github.io]-[/usr/share/doc/kernel-doc-4.18.0/Documentation/cgroup-v1]
└─$cat 00-INDEX
。。。。。。。
memcg_test.txt
- Memory Resource Controller; implementation details.
memory.txt
- Memory Resource Controller; design, accounting, interface, testing.
。。。。。。。。。。。。。。。。。。。。。
┌──[root@liruilongs.github.io]-[/usr/share/doc/kernel-doc-4.18.0/Documentation/cgroup-v1]
└─$1.2.3.4.5.6.7.8.9.10.
Cgroup 限制内存资源常见的有两种,一种是 通过 systemd,一种是直接通过 cgroup 文件系统进行配置,这里我们先介绍通过 systemd 的方式配置,因为这种方式比较简单,而且可以做到进程级别的配置,而通过 cgroup 的方式,可以做到系统级别的配置,前提是当前Linux 机器使用 systemd,并且所有启动进程纳管到了 cgroup 子树,那么可以通过限制顶层树的资源限制,来实现整个系统的资源限制。
在 systemd 的 drop-in 文件文件[Service]段里面定义 MemoryLimit 值就可以限制你的程序所使用的内存,单位可以是K,M,G或T。
这里看一个以临时服务的方式运行 /bin/bash命令的Demo ,对 内存和CPU 进行限制, 并将其标准输入、标准输出、标准错误连接到当前的 TTY 设备上:
复制
┌──[root@liruilongs.github.io]-[~]
└─$ systemd-run -p MemoryLimit=5M -p CPUShares=100 --unit=bash-limit --slice=bash-test -t /bin/bash
Running as unit bash-limit.service.
Press ^] three times within 1s to disconnect TTY.1.2.3.4.
在生成的 bash Service 中我们可以运行交互命令,查看当前 Service 的单元文件,MemoryLimit=5242880 ,即限制内存使用量 5M。
复制
┌──[root@liruilongs.github.io]-[/]
└─$ systemctl cat bash-limit.service
# /run/systemd/system/bash-limit.service
# Transient stub
# /run/systemd/system/bash-limit.service.d/50-CPUShares.conf
[Service]
CPUShares=100
# /run/systemd/system/bash-limit.service.d/50-Description.conf
[Unit]
Description=/bin/bash
# /run/systemd/system/bash-limit.service.d/50-Environment.conf
[Service]
Environment="TERM=xterm-256color"
# /run/systemd/system/bash-limit.service.d/50-ExecStart.conf
[Service]
ExecStart=
ExecStart=@/bin/bash "/bin/bash"
# /run/systemd/system/bash-limit.service.d/50-MemoryLimit.conf
[Service]
MemoryLimit=5242880
# /run/systemd/system/bash-limit.service.d/50-Slice.conf
。。。。。。。。。。。。。。。。。。。。。。。。1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.
通过 systemctl status bash-limit.service 我们可以看到cgroup的相关信息。
复制
┌──[root@liruilongs.github.io]-[/]
└─$ systemctl status bash-limit.service
● bash-limit.service - /bin/bash
Loaded: loaded (/run/systemd/system/bash-limit.service; static; vendor preset: disabled)
Drop-In: /run/systemd/system/bash-limit.service.d
└─50-CPUShares.conf, 50-Description.conf, 50-Environment.conf, 50-ExecStart.conf, 50-MemoryLimit.conf, 50-Slice.conf, 50-StandardError.conf, 50-StandardInput.conf, 50-StandardOutput.conf, 50-TTYPath.conf
Active: active (running) since 六 2022-10-29 13:40:19 CST; 31s ago
Main PID: 136529 (bash)
Memory: 1.7M (limit: 5.0M)
CGroup: /bash.slice/bash-test.slice/bash-limit.service
├─136529 /bin/bash
└─136607 systemctl status bash-limit.service
10月 29 13:40:19 liruilongs.github.io systemd[1]: Started /bin/bash.
┌──[root@liruilongs.github.io]-[/]
└─$ bash
┌──[root@liruilongs.github.io]-[/]
└─$ bash1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.
bash-limit.service 这个 service 的上级子树为 bash.slice 这个分组。
复制
Memory: 1.7M (limit: 5.0M)
CGroup: /bash.slice/bash-test.slice/bash-limit.service
├─136529 /bin/bash
└─136607 systemctl status bash-limit.service1.2.3.4.
当然上面的配置方式实际上是基于 Cgroup 来实现的,Cgroup V1 版本和 V2 版本有些区别,当前机器环境的问题,我们只看一下 V1 的版本,MemoryLimit 参数可以控制Cgroup 内存控制器的 memory.limit_in_bytes Cgroup参数。
对于运行中的 service 可以直接通过set-property 的方式来修改。
复制
# 如需使用命令列来限定 httpd.service 的 CPU 和内存占用量,请输入:
systemctl set-property httpd.service CPUShares=600 MemoryLimit=500M1.2.
下面为 system.slice 这个 Cgroup 分组下面 tuned Cgroup 内存相关资源限制,可以看到默认的情况下没有限制(memory.limit_in_bytes ),使用的最大值,这里的内存限制是物理内存,不是虚拟内存。
tuned 小伙伴们应该不陌生,一个开源的系统性能优化的服务,用于一些内核参数限制。
复制
┌──[root@liruilongs.github.io]-[/sys/fs/cgroup/memory/system.slice]
└─$cat tuned.service/memory.
memory.events memory.kmem.tcp.failcnt memory.memsw.failcnt memory.qos_level
memory.events.local memory.kmem.tcp.limit_in_bytes memory.memsw.limit_in_bytes memory.soft_limit_in_bytes
memory.failcnt memory.kmem.tcp.max_usage_in_bytes memory.memsw.max_usage_in_bytes memory.stat
memory.force_empty memory.kmem.tcp.usage_in_bytes memory.memsw.usage_in_bytes memory.swappiness
memory.high memory.kmem.usage_in_bytes memory.min memory.usage_in_bytes
memory.kmem.failcnt memory.limit_in_bytes memory.move_charge_at_immigrate memory.use_hierarchy
memory.kmem.limit_in_bytes memory.low memory.numa_stat
memory.kmem.max_usage_in_bytes memory.max_usage_in_bytes memory.oom_control
memory.kmem.slabinfo memory.memfs_files_info memory.pressure_level1.2.3.4.5.6.7.8.9.10.11.
默认情况下,没有限制会显示最大值。
复制
┌──[root@liruilongs.github.io]-[/sys/fs/cgroup/memory/system.slice]
└─$cat tuned.service/memory.limit_in_bytes
92233720368547717121.2.3.
配置方式我们可以通过上面的方式配置,通过 service unit 文件进行限制。
限定最大可用内存为 1GB,添加 MemoryLimit 设定。
复制
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system]
└─$vim tuned.service1.2.
确认配置,加载配置文件,重启。
复制
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system]
└─$systemctl cat tuned.service
# /usr/lib/systemd/system/tuned.service
[Unit]
Description=Dynamic System Tuning Daemon
After=systemd-sysctl.service network.target dbus.service
Requires=dbus.service polkit.service
Conflicts=cpupower.service auto-cpufreq.service tlp.service power-profiles-daemon.service
Documentation=man:tuned(8) man:tuned.conf(5) man:tuned-adm(8)
[Service]
Type=dbus
MemoryLimit=1G
PIDFile=/run/tuned/tuned.pid
BusName=com.redhat.tuned
ExecStart=/usr/sbin/tuned -l -P
Restart=on-failure
[Install]
WantedBy=multi-user.target
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system]
└─$systemctl daemon-reload
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system]
└─$systemctl restart tuned.service1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.
再次查看 Cgroup 内存相关限制参数。
复制
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system]
└─$cat /sys/fs/cgroup/memory/system.slice/tuned.service/memory.limit_in_bytes
1073741824
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system]
└─$1.2.3.4.5.
生产环境,更多的是通过 drop-in 的方式定义文件。
复制
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system]
└─$vim tuned.service.d/50-MemoryLimit.conf
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system]
└─$systemctl daemon-reload
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system]
└─$systemctl restart tuned.service
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system]
└─$systemctl cat tuned.service
# /usr/lib/systemd/system/tuned.service
[Unit]
Description=Dynamic System Tuning Daemon
After=systemd-sysctl.service network.target dbus.service
Requires=dbus.service polkit.service
Conflicts=cpupower.service auto-cpufreq.service tlp.service power-profiles-daemon.service
Documentation=man:tuned(8) man:tuned.conf(5) man:tuned-adm(8)
[Service]
Type=dbus
PIDFile=/run/tuned/tuned.pid
BusName=com.redhat.tuned
ExecStart=/usr/sbin/tuned -l -P
Restart=on-failure
[Install]
WantedBy=multi-user.target
# /usr/lib/systemd/system/tuned.service.d/50-MemoryLimit.conf
[Service]
MemoryLimit=1G
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system]
└─$1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.
这里我们简单看一下,其他的 Cgroup 参数限制,部分参数在 Cgroup V2 中作了调整,感兴趣小伙伴可以看看去。
核心内存限制
参数
作用
memory.limit_in_bytes
物理内存硬限制
(单位:字节),超出会触发 OOM Killer。
memory.memsw.limit_in_bytes
物理内存 + swap 总限制
(需内核启用 swapaccount=1)。
memory.soft_limit_in_bytes
内存软限制
,系统优先回收超过此值的内存,但不会强制杀死进程。
内核内存控制
参数
作用
memory.kmem.limit_in_bytes
内核内存(如 slab、dentry 缓存)的硬限制
。
memory.kmem.tcp.limit_in_bytes
TCP 缓冲区内存的硬限制
(如 TCP socket 发送/接收缓冲区)。
内存回收与行为控制
参数
作用
memory.force_empty
强制释放内存缓存
(写入 0 触发)。
memory.swappiness
调整内存回收策略
(值越高,系统越积极使用 swap)。
memory.oom_control
控制 OOM Killer 行为
(0 表示启用 OOM Killer,1 表示禁用)。
memory.move_charge_at_immigrate
进程迁移时是否转移内存占用
(1 表示转移)。
高级功能
参数
作用
memory.high
内存使用软限制
(v1 中较少使用,v2 中更常见)。
memory.low
内存保护阈值
,系统尽量避免回收低于此值的内存。
memory.pressure_level
内存压力事件通知
(需配合 cgroup.event_control 使用)。
对于这部分参数的配置,可以直接找到对应的 Cgroup 文件进行修改。
复制
# 限制 TCP 缓冲区为 100MB
echo "100M" > memory.kmem.tcp.limit_in_bytes1.2.
ulimit
对于多用户的系统不限制资源本身可能就是一种不公平, 限制系统资源比较老的方式是使用 ulimit,由 PAM 模块在登录和会话启动时强制实施,ulimit 命令是bash 内置命令,主要限制了 shell 及其子进程可用的资源。
在/etc/pam.d/system-auth 文件中调用了 pam_limits 模块,此模块读取 /etc/security/limits.conf 和/etc/security/limits.d/,按配置文件设置资源限制。 查看模块帮助文档 man pam limits。
/etc/pam.d/system-auth 是什么?
/etc/pam.d/system-auth 是一个 PAM(Pluggable Authentication Modules)配置文件。在 Linux 系统中,PAM 提供了一种灵活的方式来配置用户认证、授权和会话管理。
该文件是一个包含 PAM 配置行的文本文件,用于定义不同的认证、授权和会话模块及其参数。PAM 模块负责处理用户登录、密码验证、权限检查等操作。
查看文件中资源限制相关的模块,有时候我们做一些基线整改,可能需要修改该文件的相关配置。
复制
┌──[root@liruilongs.github.io]-[~]
└─$cat /etc/pam.d/system-auth | grep pam_limits
session required pam_limits.so
┌──[root@liruilongs.github.io]-[~]
└─$1.2.3.4.5.
在PAM配置中,pam_limits.so 模块被要求进行会话限制。
PAM(Pluggable Authentication Modules)是一个用于对用户进行认证的系统级框架。pam_limits.so 模块是 PAM 框架的一部分,它用于设置会话级别的资源限制,例如进程可打开的文件数、进程可使用的内存等。
ulimit 命令是用于限制用户级别资源的工具,它通常用于控制 shell 进程及其子进程的资源使用。修改 ulimit 值只会对当前 shell 会话有效,对其他用户或系统进程不会产生影响(不一定)。
通过 ulimit 是限制系统资源的一种途径,ulimit 支持 hard 和 soft 限制。
复制
#<type> can have the two values:
# - "soft" for enforcing the soft limits
# - "hard" for enforcing hard limits
#
#<item> can be one of the following:
# - core - limits the core file size (KB)
# - data - max data size (KB)
# - fsize - maximum filesize (KB)
# - memlock - max locked-in-memory address space (KB)
# - nofile - max number of open file descriptors
# - rss - max resident set size (KB)
# - stack - max stack size (KB)
# - cpu - max CPU time (MIN)
# - nproc - max number of processes
# - as - address space limit (KB)
# - maxlogins - max number of logins for this user
# - maxsyslogins - max number of logins on the system
# - priority - the priority to run user process with
# - locks - max number of file locks the user can hold
# - sigpending - max number of pending signals
# - msgqueue - max memory used by POSIX message queues (bytes)
# - nice - max nice priority allowed to raise to values: [-20, 19]
# - rtprio - max realtime priority1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.
普通用户可以设置自己的软限制,但不能高于硬限制。可以使用 ulimit -a 查看资源限制列表。
软限制 (soft maxlogins):软限制是一个警告阈值,当达到或超过该限制时,系统会发出警告信息,但不会阻止用户登录。硬限制 (hard maxlogins):硬限制是一个严格的限制,当达到或超过该限制时,系统将阻止用户登录。
复制
┌──[root@liruilongs.github.io]-[~]
└─$ulimit -Hn #限制数
262144
┌──[root@liruilongs.github.io]-[~]
└─$ulimit -Sn #限制数
1024
┌──[root@liruilongs.github.io]-[~]
└─$1.2.3.4.5.6.7.8.
当指定限制数时限制,不指定时输出当前设置。
通过配置文件的方式对登录次数进行限制,配置 kiosk 组 在多个终端中只能同时登录 2 次。
复制
┌──[root@liruilongs.github.io]-[~]
└─$cat /etc/security/limits.conf | grep -v ^# | grep -v ^$
@kiosk soft maxlogins 2
@kiosk hard maxlogins 2
┌──[root@liruilongs.github.io]-[~]
└─$1.2.3.4.5.6.
涉及到内存相关的资源限制:
memlock:最大锁定内存地址空间限制(以 KB 为单位)rss:最大常驻集大小限制(以 KB 为单位)物理内存stack:最大堆栈大小限制(以 KB 为单位)as:地址空间限制(以 KB 为单位)虚拟内存msgqueue:POSIX 消息队列使用的最大内存限制(以字节为单位)
配置虚拟内存限制可以通过 ulimit 进行会话基本的虚拟内存设置,下面是一个 Demo,仅对 当前 Shell 及其子进程 生效 as 虚拟地址空间限制,以 KB 为单位。
复制
┌──[root@liruilongs.github.io]-[~]
└─$ulimit -v 8186 # 配置 当前 ulimit 大小为 8MB
┌──[root@liruilongs.github.io]-[~]
└─$ls
ls: error while loading shared libraries: libc.so.6: failed to map segment from shared object1.2.3.4.5.
修改 as 的大小之后,提示 ls 命令无法加载共享库 libc.so.6,并且无法从共享对象映射段。
永久配置(全局或用户级)需要修改 /etc/security/limits.conf, 感兴趣小伙伴可以看看我之前的博文,生效条件:用户重新登录后生效。
复制
# 格式:<domain> <type> <item> <value>
liruilong hard as 819200 # Hard Limit 800MB
liruilong soft as 409600 # Soft Limit 400MB1.2.3.
其他的一些限制项,也可以通过上面的方式进行,比如内存锁定,最大栈,数据段等内存相关的限制。
内核参数
通过内核参数对内存的限制主要是一些缓存区的内存占用限制,以及部分 OOM 和 内存使用策略的修改,内存页分配限制策略等。
这里关于怎么修改内核参数以及内核参数的加载方式,可以参考我之前的博文,这里就不再赘述了。
缓存区内存限制
下面为通过关键字过滤部分的内核参数。
复制
[root@developer ~]# sysctl -a | grep mem
kernel.bind_memcg_blkcg_enable = 1
net.core.optmem_max = 81920
net.core.rmem_default = 212992
net.core.rmem_max = 212992
net.core.wmem_default = 212992
net.core.wmem_max = 212992
net.ipv4.fib_sync_mem = 524288
net.ipv4.igmp_max_memberships = 20
net.ipv4.tcp_mem = 78777105039157554
net.ipv4.tcp_rmem = 40961310726291456
net.ipv4.tcp_wmem = 4096163844194304
net.ipv4.udp_mem = 157557210078315114
net.ipv4.udp_rmem_min = 4096
net.ipv4.udp_wmem_min = 4096
vm.hugepage_pmem_allocall = 0
vm.hugetlb_optimize_vmemmap = 0
vm.lowmem_reserve_ratio = 256256320
vm.memcg_qos_enable = 0
vm.memcg_swap_qos_enable = 0
vm.memory_failure_early_kill = 0
vm.memory_failure_recovery = 1
vm.nr_hugepages_mempolicy = 0
vm.overcommit_memory = 0
[root@developer ~]#1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.
缓存区的话,一般用的比较多的是网络方面的,比如 TCP,UDP,Stock 等。这部分参数没有固定的值,一般根据机器使用场景动态设置。
在上面的输出中,前部位为 socket 级别的网络缓存区限制,socket接受和发送数据的缓存的最大值,这里的配置往往结合 BDP 进行配置,感兴趣小伙伴可以看看我之前网络调优的博文。
复制
net.core.optmem_max = 81920
net.core.rmem_default = 212992
net.core.rmem_max = 212992
net.core.wmem_default = 212992
net.core.wmem_max = 2129921.2.3.4.5.
后部分为 TCP/UDP 级别的网络缓存区限制,TCP 缓冲区的大小应根据系统和网络的需求进行调整。较大的缓冲区可以提高网络性能,特别是在高负载或高延迟的网络环境中。但是,过大的缓冲区可能会导致内存占用增加或延迟问题。
net.ipv4.tcp_rmem 和 net.ipv4.tcp_wmem 用于配置 TCP 套接字的接收缓冲区和发送缓冲区的大小。
复制
net.ipv4.tcp_rmem = 40961310726291456
net.ipv4.tcp_wmem = 4096163844194304
net.ipv4.udp_rmem_min = 4096
net.ipv4.udp_wmem_min = 40961.2.3.4.
下面的两个为 系统级别内存限制,单位是Page 内存页,4K,分别代表了TCP和UDP的系统层面内存限制的值,即网络连接的内存分配,包括三列:min,pressure,max。
复制
net.ipv4.tcp_mem = 78777 105039 157554
net.ipv4.udp_mem = 157557 210078 3151141.2.
这里格式有点问题,我们换一个方式查看。
复制
[root@developer ~]# cat /proc/sys/net/ipv4/tcp_mem
78777 105039 157554
[root@developer ~]#1.2.3.
内存超售限制
下面这组内核参数用于限制内存的超售问题,内存的分配和使用是两个阶段,在分配的时候是虚拟内存,而且实际使用才会分配物理内存,对于虚拟内存的分配,可以是一个很大的值,但是物理内存的分配,是有限制的,如果分配的虚拟内存大于物理内存,那么就会导致内存超售,那么这个时候,就需要限制内存的超售问题,避免内存超售导致系统崩溃。
复制
[root@developer ~]# sysctl -a | grep overcomm
vm.nr_overcommit_hugepages = 0
vm.overcommit_kbytes = 0
vm.overcommit_memory = 0
vm.overcommit_ratio = 501.2.3.4.5.
vm.overcommit_memory = 0 :控制内核的内存超分配策略,决定是否允许进程申请超过物理内存 + Swap 的空间。
0(默认):启发式超分配(Heuristic Overcommit)。内核根据当前空闲内存、可回收缓存(PageCache/SLAB)和 Swap 综合判断是否允许分配。若申请量显著超过可用资源则拒绝。1:无条件允许超分配(Always Overcommit)。来者不拒,但可能因实际内存不足触发 OOM Killer。2:禁止超分配(Never Overcommit)。严格限制分配总量 ≤ (物理内存 × overcommit_ratio%) + Swap。
vm.overcommit_ratio = 50: 当 overcommit_memory=2 时,定义物理内存的可超配比例(默认值 50%)。 计算公式: CommitLimit = (物理内存 × overcommit_ratio / 100) + Swap 。
vm.overcommit_kbytes = 0:与 overcommit_ratio 互斥,直接指定超配的字节级上限(优先级高于 ratio)。
vm.nr_overcommit_hugepages = 0:控制标准大页(HugePages)的超配数量,允许临时分配超出 vm.nr_hugepages 预设值的大页。
上面讲到了大页,这里我们顺便看看内存页相关的内存限制。
内存页限制
hugepages 用于限制分配的大页数量,这里的大页指的是标准大页,即 2MB 的大页。
复制
sysctl -w vm.nr_hugepages=1024 # 分配1024个大页(默认2MB/页)1.
如果需要自定义大页的大小,比如 1GB 的大页,需要通过 hugepagesz 来进行限制,一般启动时通过GRUB配置。
复制
hugepagesz=1G hugepages=4 default_hugepagesz=1G # 分配4个1GB大页1.
关于内存页,内核相关的参数中还有透明大页的配置,比如透明大页的开启,khugepaged 进程的扫描频率等等,感兴趣的小伙伴可以看看我之前关于大页的博文。
下面为脏页/换页/内存回收与保留相关参数的内存限制。
脏页指内存中已被修改但未写入磁盘的数据页。内核通过以下参数控制其回写行为:
复制
[root@developer ~]# sysctl -a | grep dirty
vm.dirty_background_bytes = 0 # 触发后台异步刷盘的脏页绝对字节阈值(优先级高于ratio)。0表示未启用,使用dirty_background_ratio控制
vm.dirty_background_ratio = 10 # 触发后台异步刷盘的脏页内存占比阈值(默认10%)。脏页超限时内核启动后台线程异步刷盘,不阻塞应用
vm.dirty_bytes = 0 # 触发同步阻塞刷盘的脏页绝对字节阈值(优先级高于ratio)。0表示未启用,使用dirty_ratio控制
vm.dirty_expire_centisecs = 3000 # 脏页在内存中的最长存活时间(默认3000=30秒)。超时后强制刷盘,减少数据丢失风险
vm.dirty_ratio = 30 # 触发同步阻塞刷盘的脏页内存占比阈值(默认30%)。超限时应用写入被阻塞,直至脏页落盘
vm.dirty_writeback_centisecs = 500 # 内核刷盘线程的唤醒间隔(默认500=5秒)。值越小刷盘越频繁,过高可能导致I/O堆积
vm.dirtytime_expire_seconds = 43200 # 仅修改时间(atime/mtime)的脏元数据超时时间(默认43200=12小时)。通常无需调整1.2.3.4.5.6.7.8.
下面为交换分区使用限制:
复制
vm.memcg_swap_qos_enable = 0 # 内存控制组(memcg)的Swap服务质量(QoS)功能开关
vm.swap_extension = 0 # 扩展Swap空间的机制(通常用于特殊场景,如内存压缩)
vm.swappiness = 30 # 控制内核使用Swap的倾向性(范围0-100)1.2.3.
还有两个特殊的参数需要单独说明一下:
vm.min_free_kbytes:系统保留的最小空闲内存(单位 KB),用于应对突发需求。vm.watermark_scale_factor:调整内存回收敏感度(默认 10,范围 1-1000)。
复制
[root@developer ~]# sysctl -a | grep min_free_kbytes
vm.min_free_kbytes = 45056
[root@developer ~]# sysctl -a | grep watermark_scale_factor
vm.watermark_scale_factor = 10
[root@developer ~]#1.2.3.4.5.
OOM 相关内存限制
下面为OOM相关,的内存限制,关于 OOM 是什么,什么原理不是本文重点,小伙伴可以看看我之前的博文。
复制
[root@developer ~]# sysctl -a | grep oom
vm.enable_oom_killer = 1 # 启用OOM Killer机制(默认值)。当系统内存耗尽时,内核自动终止进程释放内存
vm.oom_dump_tasks = 1 # OOM触发时记录所有进程的内存状态到日志(/var/log/messages),便于事后分析
vm.oom_kill_allocating_task = 0 # 禁用“直接杀死触发OOM的进程”。内核会扫描所有进程,选择badness分数最高的进程终止
vm.panic_on_oom = 0 # OOM时禁止内核崩溃(panic)。0表示调用OOM Killer而非重启系统(生产环境推荐
[root@developer ~]#1.2.3.4.5.6.
NUMA内存限制
复制
[root@developer ~]# sysctl -a | grep zone_reclaim_mode
vm.zone_reclaim_mode = 0 # 关闭本地NUMA节点内存强制回收。允许从其他节点分配内存,避免因本地回收降低性能
[root@developer ~]# sysctl -a | grep min_unmapped_ratio
vm.min_unmapped_ratio = 1 # 每个NUMA节点保留1%的未映射内存(用于临时内存分配)
[root@developer ~]#1.2.3.4.5.
对于内存资源的限制内核参数还有很多,这里只是列举了部分。