内存与 OOM58 条

mlock 锁定内存

mlock/mlockall 把页面锁定在内存中避免换出,用于低延迟场景;受 RLIMIT_MEMLOCK 限制,服务可配 LimitMEMLOCK。

什么是 mlock

mlock()/mlockall() 把指定内存页锁定在物理内存中,禁止内核换出到 swap,从而保证访问延迟可预测:实时计算、音频处理、数据库的共享缓冲、加密密钥常这么做。代价是这部分内存不可回收,锁定过多会挤压系统可用内存。普通用户受 RLIMIT_MEMLOCK 限制,服务通过 systemd 的 LimitMEMLOCK 单独放开比改全局 limits.conf 更收敛。

基本信息

接口mlock(2) / mlockall(2),配套 munlock/munlockall
限制项RLIMIT_MEMLOCK(ulimit -l)
放宽方式systemd: LimitMEMLOCK=infinity
绕过方式CAP_IPC_LOCK 能力
观测grep Locked /proc/meminfo,或 /proc/<pid>/status 的 VmLck

典型使用场景

  • 实时业务:需要避免换页抖动带来的尾延迟,把关键缓冲区锁定
  • 数据库与缓存服务:把共享缓冲池锁定,防止突发使用触发换页
  • 安全敏感进程:密钥与凭据锁定后降低被换出到磁盘的风险
  • 对内存限制敏感的服务排障:报 Cannot allocate memory 时确认是否卡在 memlock 限制上
  • 容器与微服务:在 compose/systemd 里给单个服务放宽,而不是全局放开

查看与放行

查看与放行
ulimit -l                                  # 当前会话的 memlock 限额(KB)
grep -i locked /proc/meminfo                # 系统已锁定内存总量
grep VmLck /proc/<pid>/status                # 单进程锁定字节数
systemctl show myservice -p LimitMEMLOCK     # 服务级限额
# 服务单元里放行:LimitMEMLOCK=infinity 后 systemctl daemon-reload && restart

常见取值与含义

取值含义注意
64KB 量级默认软/硬限制,很多发行版就是这么小单进程锁不了多少内存
unlimited服务已显式放开要核算所有实例的锁定总量
VmLck 持续增长进程不断加锁结合业务确认是有意行为还是泄漏
Locked 接近物理内存系统几乎无可回收余量OOM 风险显著上升
limits.conf 的 memlock 只对新登录会话生效,已经在跑的服务必须重启才能拿到新限额。
锁定内存不可回收:风控、缓存类服务盲目 mlockall 会让系统在内存紧张时失去缓冲空间,直接放大 OOM 概率。
容器里 ulimit -l 的数值由运行时下发:Docker 用 --ulimit memlock=-1 放宽,Kubernetes 需通过 securityContext 或运行时配置调整,在宿主侧改 limits.conf 不会自动传到容器里。
评估锁定量时按“单进程上限 × 实例数”估算并留出系统余量:把每个实例的限额简单相加,结果往往已经超过物理内存,纸面上算清再放行。

易错点

  • 锁定内存不可回收,滥用会加剧系统内存压力,最终把别的服务推向 OOM
  • 默认限额较小(常为 64KB 量级),服务需显式放开并评估所有实例的锁定总量
  • 给服务加 CAP_IPC_LOCK 或 LimitMEMLOCK 比全局改 limits.conf 更安全,但改了配置不重启进程不会生效
  • 在容器里 ulimit -l 的值由容器运行时决定,宿主侧调大不代表容器内生效

数据来源与参考

  • man-pages mlock(2)
  • systemd.exec 手册
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌