首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Linux 内存调优之如何限制进程、系统级别内存资源

Linux 内存调优之如何限制进程、系统级别内存资源

作者头像
山河已无恙
发布2025-08-06 18:46:13
发布2025-08-06 18:46:13
35500
代码可运行
举报
文章被收录于专栏:山河已无恙山河已无恙
运行总次数:0
代码可运行

写在前面

  • 博文内容涉及 通过 Cgroup ,ulimit,内核参数等限制进程、系统级别内存资源
  • 理解不足小伙伴帮忙指正 :),生活加油

我看远山,远山悲悯

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

限制内存使用量

今天和小伙伴分享一些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 目录下找相关管理器的说明文档,从而配置合适的资源限制

代码语言:javascript
代码运行次数:0
运行
复制
┌──[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
................

简单的信息可以通过索引文件的了解

代码语言:javascript
代码运行次数:0
运行
复制
┌──[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]
└─$

Cgroup 限制内存资源常见的有两种,一种是 通过 systemd,一种是直接通过 cgroup 文件系统进行配置,这里我们先介绍通过 systemd 的方式配置,因为这种方式比较简单,而且可以做到进程级别的配置,而通过 cgroup 的方式,可以做到系统级别的配置,前提是当前Linux 机器使用 systemd,并且所有启动进程纳管到了 cgroup 子树,那么可以通过限制顶层树的资源限制,来实现整个系统的资源限制。

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

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

代码语言:javascript
代码运行次数:0
运行
复制
┌──[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 的单元文件,MemoryLimit=5242880 ,即限制内存使用量 5M

代码语言:javascript
代码运行次数:0
运行
复制
┌──[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的相关信息

代码语言:javascript
代码运行次数:0
运行
复制
┌──[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

bash-limit.service 这个 service 的上级子树为 bash.slice 这个分组。

代码语言:javascript
代码运行次数:0
运行
复制
   Memory: 1.7M (limit: 5.0M)
   CGroup: /bash.slice/bash-test.slice/bash-limit.service
           ├─136529 /bin/bash
           └─136607 systemctl status bash-limit.service

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

对于运行中的 service 可以直接通过set-property 的方式来修改

代码语言:javascript
代码运行次数:0
运行
复制
# 如需使用命令列来限定 httpd.service 的 CPU 和内存占用量,请输入:
systemctl set-property httpd.service CPUShares=600 MemoryLimit=500M

下面为 system.slice 这个 Cgroup 分组下面 tuned Cgroup 内存相关资源限制,可以看到默认的情况下没有限制(memory.limit_in_bytes ),使用的最大值,这里的内存限制是物理内存,不是虚拟内存,

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

代码语言:javascript
代码运行次数:0
运行
复制
┌──[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               

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

代码语言:javascript
代码运行次数:0
运行
复制
┌──[root@liruilongs.github.io]-[/sys/fs/cgroup/memory/system.slice] 
└─$cat tuned.service/memory.limit_in_bytes 
9223372036854771712

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

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

代码语言:javascript
代码运行次数:0
运行
复制
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] 
└─$vim tuned.service 

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

代码语言:javascript
代码运行次数:0
运行
复制
┌──[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 内存相关限制参数

代码语言:javascript
代码运行次数:0
运行
复制
┌──[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 的方式定义文件

代码语言:javascript
代码运行次数:0
运行
复制
┌──[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 使用)。

对于这部分参数的配置,可以直接找到对应的 Cgroup 文件进行修改

代码语言:javascript
代码运行次数:0
运行
复制
# 限制 TCP 缓冲区为 100MB
echo "100M" > memory.kmem.tcp.limit_in_bytes

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 模块负责处理用户登录、密码验证、权限检查等操作。

查看文件中资源限制相关的模块,有时候我们做一些基线整改,可能需要修改该文件的相关配置

代码语言:javascript
代码运行次数:0
运行
复制
┌──[root@liruilongs.github.io]-[~]
└─$cat /etc/pam.d/system-auth  | grep pam_limits
session     required                                     pam_limits.so
┌──[root@liruilongs.github.io]-[~]
└─$

PAM配置中,pam_limits.so 模块被要求进行会话限制

PAM(Pluggable Authentication Modules)是一个用于对用户进行认证的系统级框架。pam_limits.so 模块是 PAM 框架的一部分,它用于设置会话级别的资源限制,例如进程可打开的文件数、进程可使用的内存等。

ulimit 命令是用于限制用户级别资源的工具,它通常用于控制 shell 进程及其子进程的资源使用。修改 ulimit 值只会对当前 shell 会话有效,对其他用户或系统进程不会产生影响(不一定)

通过 ulimit 是限制系统资源的一种途径,ulimit 支持 hardsoft 限制

代码语言:javascript
代码运行次数:0
运行
复制
#<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 priority

普通用户可以设置自己的软限制,但不能高于硬限制。可以使用 ulimit -a 查看资源限制列表

软限制 (soft maxlogins):软限制是一个警告阈值,当达到或超过该限制时,系统会发出警告信息,但不会阻止用户登录。硬限制 (hard maxlogins):硬限制是一个严格的限制,当达到或超过该限制时,系统将阻止用户登录。

代码语言:javascript
代码运行次数:0
运行
复制
┌──[root@liruilongs.github.io]-[~]
└─$ulimit -Hn #限制数
262144
┌──[root@liruilongs.github.io]-[~]
└─$ulimit -Sn #限制数
1024
┌──[root@liruilongs.github.io]-[~]
└─$

当指定限制数时限制,不指定时输出当前设置

通过配置文件的方式对登录次数进行限制,配置 kiosk 组 在多个终端中只能同时登录 2 次

代码语言:javascript
代码运行次数:0
运行
复制
┌──[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]-[~]
└─$

涉及到内存相关的资源限制

  • memlock:最大锁定内存地址空间限制(以 KB 为单位)
  • rss:最大常驻集大小限制(以 KB 为单位)物理内存
  • stack:最大堆栈大小限制(以 KB 为单位)
  • as:地址空间限制(以 KB 为单位)虚拟内存
  • msgqueue:POSIX 消息队列使用的最大内存限制(以字节为单位)

配置虚拟内存限制可以通过 ulimit 进行会话基本的虚拟内存设置,下面是一个 Demo,仅对 当前 Shell 及其子进程 生效 as 虚拟地址空间限制,以 KB 为单位

代码语言:javascript
代码运行次数:0
运行
复制
┌──[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, 感兴趣小伙伴可以看看我之前的博文,生效条件:用户重新登录后生效。

代码语言:javascript
代码运行次数:0
运行
复制
# 格式:<domain>  <type>  <item>  <value>
liruilong  hard  as      819200   # Hard Limit 800MB
liruilong  soft  as      409600   # Soft Limit 400MB

其他的一些限制项,也可以通过上面的方式进行,比如内存锁定,最大栈,数据段等内存相关的限制

内核参数

通过内核参数对内存的限制主要是一些缓存区的内存占用限制,以及部分 OOM 和 内存使用策略的修改,内存页分配限制策略等

这里关于怎么修改内核参数以及内核参数的加载方式,可以参考我之前的博文,这里就不再赘述了

缓存区内存限制

下面为通过关键字过滤部分的内核参数

代码语言:javascript
代码运行次数:0
运行
复制
[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 ~]# 

缓存区的话,一般用的比较多的是网络方面的,比如 TCP,UDP,Stock 等。这部分参数没有固定的值,一般根据机器使用场景动态设置

在上面的输出中,前部位为 socket 级别的网络缓存区限制,socket接受和发送数据的缓存的最大值,这里的配置往往结合 BDP 进行配置,感兴趣小伙伴可以看看我之前网络调优的博文。

代码语言:javascript
代码运行次数:0
运行
复制
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

后部分为 TCP/UDP 级别的网络缓存区限制,TCP 缓冲区的大小应根据系统和网络的需求进行调整。较大的缓冲区可以提高网络性能,特别是在高负载或高延迟的网络环境中。但是,过大的缓冲区可能会导致内存占用增加或延迟问题。

net.ipv4.tcp_rmem 和 net.ipv4.tcp_wmem 用于配置 TCP 套接字的接收缓冲区和发送缓冲区的大小。

代码语言:javascript
代码运行次数:0
运行
复制
net.ipv4.tcp_rmem = 40961310726291456
net.ipv4.tcp_wmem = 4096163844194304
net.ipv4.udp_rmem_min = 4096
net.ipv4.udp_wmem_min = 4096

下面的两个为 系统级别内存限制,单位是Page 内存页,4K,分别代表了TCP和UDP的系统层面内存限制的值,即网络连接的内存分配,包括三列:min,pressure,max.

代码语言:javascript
代码运行次数:0
运行
复制
net.ipv4.tcp_mem = 78777  105039  157554
net.ipv4.udp_mem = 157557 210078  315114

这里格式有点问题,我们换一个方式查看

代码语言:javascript
代码运行次数:0
运行
复制
[root@developer ~]# cat /proc/sys/net/ipv4/tcp_mem
78777 105039  157554
[root@developer ~]# 

内存超售限制

下面这组内核参数用于限制内存的超售问题,内存的分配和使用是两个阶段,在分配的时候是虚拟内存,而且实际使用才会分配物理内存,对于虚拟内存的分配,可以是一个很大的值,但是物理内存的分配,是有限制的,如果分配的虚拟内存大于物理内存,那么就会导致内存超售,那么这个时候,就需要限制内存的超售问题,避免内存超售导致系统崩溃。

代码语言:javascript
代码运行次数:0
运行
复制
[root@developer ~]# sysctl -a | grep overcomm
vm.nr_overcommit_hugepages = 0
vm.overcommit_kbytes = 0
vm.overcommit_memory = 0
vm.overcommit_ratio = 50

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 的大页,

代码语言:javascript
代码运行次数:0
运行
复制
sysctl -w vm.nr_hugepages=1024  # 分配1024个大页(默认2MB/页)

如果需要自定义大页的大小,比如 1GB 的大页,需要通过 hugepagesz 来进行限制,一般启动时通过GRUB配置

代码语言:javascript
代码运行次数:0
运行
复制
hugepagesz=1G hugepages=4 default_hugepagesz=1G  # 分配4个1GB大页

关于内存页,内核相关的参数中还有透明大页的配置,比如透明大页的开启,khugepaged 进程的扫描频率等等,感兴趣的小伙伴可以看看我之前关于大页的博文

下面为脏页/换页/内存回收与保留相关参数的内存限制

脏页指内存中已被修改但未写入磁盘的数据页。内核通过以下参数控制其回写行为:

代码语言:javascript
代码运行次数:0
运行
复制
[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小时)。通常无需调整

下面为交换分区使用限制

代码语言:javascript
代码运行次数:0
运行
复制
vm.memcg_swap_qos_enable = 0   # 内存控制组(memcg)的Swap服务质量(QoS)功能开关
vm.swap_extension = 0          # 扩展Swap空间的机制(通常用于特殊场景,如内存压缩)
vm.swappiness = 30             # 控制内核使用Swap的倾向性(范围0-100)

还有两个特殊的参数需要单独说明一下:

  • vm.min_free_kbytes:系统保留的最小空闲内存(单位 KB),用于应对突发需求
  • vm.watermark_scale_factor:调整内存回收敏感度(默认 10,范围 1-1000)。
代码语言:javascript
代码运行次数:0
运行
复制
[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 ~]# 

OOM 相关内存限制

下面为OOM相关,的内存限制,关于 OOM 是什么,什么原理不是本文重点,小伙伴可以看看我之前的博文

代码语言:javascript
代码运行次数:0
运行
复制
[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 ~]#

NUMA内存限制

代码语言:javascript
代码运行次数:0
运行
复制
[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 ~]#  

对于内存资源的限制内核参数还有很多,这里只是列举了部分。关于Linux 内存资源限制就和小伙伴分享到这里 ^_^

博文部分内容参考

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

《性能之巅 系统、企业与云可观测性(第2版)》

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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-08-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 山河已无恙 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 写在前面
  • 限制内存使用量
    • Cgroup
    • ulimit
    • 内核参数
  • 博文部分内容参考
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档