Linux 限制内存使用量:Linux 内存调优之限制进程、系统级别内存使用量

我看远山,远山悲悯

写在前面


+

  • 理解不足小伙伴帮忙指正 :),生活加油

我看远山,远山悲悯

持续分享技术干货,感兴趣小伙伴可以关注下 ^_^


限制内存使用量

systemddrop-in 文件文件[Service]段里面定义 MemoryLimit 参考就可以限制你的程序所使用的内存,单位可以是K,M,G或T。

这里看一个以临时服务的方式运行 /bin/bash命令的Demo , 并将其标准输入、标准输出、标准错误连接到当前的 TTY 设备上:

1
2
3
4
┌──[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.

在生成的 bash Service 中我们可以运行交互命令,查看当前 Service 的单元文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
┌──[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
。。。。。。。。。。。。。。。。。。。。。。。。

通过 systemctl status bash-limit.service 我们可以看到cgroup的相关信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
┌──[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]-[/]
└─$ bash

当然上面的配置方式实际上是基于 Cgroup 来实现的,Cgroup V1 版本和 V2 版本有些区别,当前机器环境的问题,我们只看一下 V1 的版本,MemoryLimit 参数可以控制Cgroup 内存控制器的 memory.limit_in_bytes Cgroup参数

下面为 system.slice 这个 Cgroup 分组下面 tuned Cgroup 内存相关资源限制,可以看到默认的情况下没有限制(memory.limit_in_bytes ),使用的最大值,这里的内存限制是物理内存,不是虚拟内存,配置虚拟内存可以通过 ulimit 进行会话基本的虚拟内存设置,下面是一个 Demo

仅对 ​​当前 Shell 及其子进程​​ 生效 as 虚拟地址空间限制,以 KB 为单位

1
2
3
4
5
┌──[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 object

修改 as 的大小之后,提示 ls 命令无法加载共享库 libc.so.6,并且无法从共享对象映射段

永久配置(全局或用户级)​需要修改 /etc/security/limits.conf, 感兴趣小伙伴可以看看我之前的博文,生效条件​​:用户重新登录后生效。

1
2
3
# 格式:<domain>  <type>  <item>  <value>
liruilong hard as 819200 # Hard Limit 800MB
liruilong soft as 409600 # Soft Limit 400MB

也可以通过 systemd 服务配置​​,修改服务的 systemd 单元文件

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
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] 
└─$prlimit
RESOURCE DESCRIPTION SOFT HARD UNITS
AS 地址空间限制 无限制 无限制 字节
CORE 最大核心文件尺寸 无限制 无限制 字节
CPU CPU 时间 无限制 无限制 秒数
DATA 最大数据尺寸 无限制 无限制 字节
FSIZE 最大文件尺寸 无限制 无限制 字节
LOCKS 最大文件锁保持数量 无限制 无限制 锁
MEMLOCK 最大内存锁定(locked-in-memory)地址空间 65536 65536 字节
MSGQUEUE POSIX 消息队列中的最大字节数 819200 819200 字节
NICE 允许提升的最大 nice 优先级 0 0
NOFILE 打开文件的最大数量 65535 65535 文件
NPROC 最大进程数 29616 29616 进程
RSS 最大驻留集尺寸 无限制 无限制 字节
RTPRIO 最大实时优先级 0 0
RTTIME 实时任务超时 无限制 无限制 毫秒数
SIGPENDING 挂起(pending)信号的最大数量 29616 29616 信号
STACK 最大栈(stack)尺寸 8388608 无限制 字节
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system]
└─$prlimit --pid=1 --as
RESOURCE DESCRIPTION SOFT HARD UNITS
AS 地址空间限制 无限制 无限制 字节
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system]
└─$
1
2
[Service]
LimitAS=819200 # 限制虚拟内存为 800MB(单位:字节)
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] 
└─$prlimit
RESOURCE DESCRIPTION SOFT HARD UNITS
AS 地址空间限制 无限制 无限制 字节
CORE 最大核心文件尺寸 无限制 无限制 字节
CPU CPU 时间 无限制 无限制 秒数
DATA 最大数据尺寸 无限制 无限制 字节
FSIZE 最大文件尺寸 无限制 无限制 字节
LOCKS 最大文件锁保持数量 无限制 无限制 锁
MEMLOCK 最大内存锁定(locked-in-memory)地址空间 65536 65536 字节
MSGQUEUE POSIX 消息队列中的最大字节数 819200 819200 字节
NICE 允许提升的最大 nice 优先级 0 0
NOFILE 打开文件的最大数量 65535 65535 文件
NPROC 最大进程数 29616 29616 进程
RSS 最大驻留集尺寸 无限制 无限制 字节
RTPRIO 最大实时优先级 0 0
RTTIME 实时任务超时 无限制 无限制 毫秒数
SIGPENDING 挂起(pending)信号的最大数量 29616 29616 信号
STACK 最大栈(stack)尺寸 8388608 无限制 字节
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system]
└─$prlimit --pid=1 --as
RESOURCE DESCRIPTION SOFT HARD UNITS
AS 地址空间限制 无限制 无限制 字节
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system]
└─$# 查看 PID=1234 的虚拟内存限制
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system]
└─$cat /proc/1/limits | grep "Max address space"
Max address space unlimited unlimited bytes
┌──[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]
└─$vim /usr/lib/systemd/system/tuned.service.d/limit-as-800.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]
└─$pgrep tuned
4677
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system]
└─$prlimit --pid=4677 --as
RESOURCE DESCRIPTION SOFT HARD UNITS
AS 地址空间限制 无限制 无限制 字节
┌──[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

# /usr/lib/systemd/system/tuned.service.d/limit-as-800.conf
[Service]
LimitAS=819200 # 限制虚拟内存为 800MB(单位:字节)
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system]
└─$cat /proc/1/limits
Limit Soft Limit Hard Limit Units
Max cpu time unlimited unlimited seconds
Max file size unlimited unlimited bytes
Max data size unlimited unlimited bytes
Max stack size 8388608 unlimited bytes
Max core file size unlimited unlimited bytes
Max resident set unlimited unlimited bytes
Max processes 29616 29616 processes
Max open files 1073741816 1073741816 files
Max locked memory 974647296 974647296 bytes
Max address space unlimited unlimited bytes
Max file locks unlimited unlimited locks
Max pending signals 29616 29616 signals
Max msgqueue size 819200 819200 bytes
Max nice priority 0 0
Max realtime priority 0 0
Max realtime timeout unlimited unlimited us
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system]
└─$

tuned 小伙伴们应该不陌生,一个开源新的系统性能优化的服务,用于一些内核参数限制

1
2
3
4
5
6
7
8
9
10
11
┌──[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_level

默认情况下,没有限制会显示最大值

1
2
3
┌──[root@liruilongs.github.io]-[/sys/fs/cgroup/memory/system.slice] 
└─$cat tuned.service/memory.limit_in_bytes
9223372036854771712

配置方式我们可以通过上面的方式配置,通过 service unit 文件进行限制

限定最大可用内存为 1GB,添加 MemoryLimit 设定

1
2
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] 
└─$vim tuned.service

确认配置,加载配置文件,重启

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
┌──[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.service

再次查看 Cgroup 内存相关限制参数

1
2
3
4
5
┌──[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]
└─$

生产环境,更多的是通过 drop-in 的方式定义文件

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
┌──[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]
└─$

这里我们简单看一下,其他的 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 使用)。

缺页异常监控

当进程访问系统没有映射物理页的虚拟内存页时,内核就会产生一个 page fault 事件。

当进程缺页事件发生在第一次访问虚拟内存时,内核会产生一个 minor page fualt,并分配新的物理内存页。minor page fault 产生的开销比较小。但是,当物理内存页丢失,并需要从硬盘中加载内存的数据信息时,内核就会产生一个 majorpage fault.

这种情况发生在,比如内核通过交互分区,将内存中的数据交换出去放到了硬盘,她就需要从硬盘中重新加载程序或库文件的代码到内存。

由于内核必须从磁盘加载页面,因此一个major fault对性能影响比较大

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
32
33
34
35
36
┌──[root@liruilongs.github.io]-[~]
└─$ps -eo pid,minflt,majflt,comm | awk '$2 > 0 && $3 > 0 {print}'
PID MINFLT MAJFLT COMMAND
1 55646 189 systemd
704 959 7 systemd-journal
719 1912 2 systemd-udevd
892 80 3 auditd
913 553 12 dbus-broker-lau
915 281 4 dbus-broker
918 15617 206 firewalld
919 325 6 irqbalance
921 740 5 systemd-logind
925 166 5 chronyd
955 1243 100 NetworkManager
991 26090 281 /usr/sbin/httpd
998 2683 260 php-fpm
999 923 17 sshd
1002 9775 7 tuned
1006 862 3 crond
1121 6976 225 mariadbd
1150 2060 125 polkitd
1213 731 24 rsyslogd
1498 390 7 pmcd
1518 516 11 pmdaroot
1535 470 4 pmdaproc
1544 410 2 pmdaxfs
1551 447 4 pmdalinux
1558 409 2 pmdakvm
1872 2109 1 /usr/sbin/httpd
1874 3701 9 /usr/sbin/httpd
2201 2654 2 bash
2245 678 6 sudo
2246 3300 1 bash
4085 541 10 htop
┌──[root@liruilongs.github.io]-[~]
└─$
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
┌──[root@liruilongs.github.io]-[~]
└─$perf stat -e minor-faults,major-faults hostnamectl
Static hostname: liruilongs.github.io
Icon name: computer-vm
Chassis: vm �
Machine ID: 7deac2815b304f9795f9e0a8b0ae7765
Boot ID: 5041b68a4d574df2b59289e33e85bdd5
Virtualization: vmware
Operating System: Rocky Linux 9.4 (Blue Onyx)
CPE OS Name: cpe:/o:rocky:rocky:9::baseos
Kernel: Linux 5.14.0-427.20.1.el9_4.x86_64
Architecture: x86-64
Hardware Vendor: VMware, Inc.
Hardware Model: VMware Virtual Platform
Firmware Version: 6.00

Performance counter stats for 'hostnamectl':

463 minor-faults
0 major-faults

0.132397887 seconds time elapsed

0.009642000 seconds user
0.004471000 seconds sys


┌──[root@liruilongs.github.io]-[~]
└─$

博文部分内容参考

© 文中涉及参考链接内容版权归原作者所有,如有侵权请告知 :)



© 2018-至今 liruilonger@gmail.com, 保持署名-非商用-相同方式共享(CC BY-NC-SA 4.0)

Linux 限制内存使用量:Linux 内存调优之限制进程、系统级别内存使用量

https://liruilongs.github.io/2025/04/15/Linux-限制内存使用量:Linux-内存调优之限制进程、系统级别内存使用量/

发布于

2025-04-15

更新于

2025-04-15

许可协议

评论
Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×