Linux内存管理全解析:从原理到实践,让你的服务器不再“内存不足”

张开发
2026/4/14 20:57:11 15 分钟阅读

分享文章

Linux内存管理全解析:从原理到实践,让你的服务器不再“内存不足”
Linux内存管理全解析从原理到实践让你的服务器不再“内存不足”在日常运维中你是否也经常看到服务器内存使用率达到90%以上然后紧急扩容实际上Linux的内存管理机制远比我们想象的要复杂和智能。今天我们就来深入探讨Linux内存管理的核心机制以及在生产环境中该如何正确理解和优化内存使用。举例企业的监控系统频繁发出内存告警显示多台服务器内存使用率超过95%。运维团队紧急排查却发现应用响应速度正常系统并未发生OOMOut Of Memory。原因Linux内核的Page Cache机制在“作祟”。当内存空闲时内核会将部分内存用于缓存磁盘数据Page Cache以加速后续的磁盘读取操作。这部分内存在应用程序需要时会立即释放因此监控中的“高内存使用率”往往是一种假象。# 查看Page Cache大小$free-htotal usedfreeshared buff/cache available Mem: 62G8.1G1.2G1.5G 53G 52G Swap: 0B 0B 0B这里的buff/cache就是Page Cache它占用了53G内存这部分内存是“可回收”的。Linux内存管理核心架构内核内存分配机制Linux 采用页式内存管理默认页大小为 4KB。内核通过 Buddy System 管理物理页使用 Slab Allocator 处理小对象分配如kmalloc请求。生产环境关键认知匿名页Anonymous Pages进程堆栈、数据段无文件 backingswap 的主要对象文件页File PagesPage Cache用于缓冲磁盘数据可被内核随时回收内核内存Kernel MemorySlab、页表、per-cpu 变量对容器环境尤为关键查看实时构成cat/sys/fs/cgroup/memory.stat# 输出示例# anon 104857600 # 100MB 匿名内存# file 52428800 # 50MB 文件缓存# kernel_stack 8192 # 内核栈占用内存回收与 OOM 机制当可用内存低于水位线watermark时kswapd 后台线程启动回收若压力持续触发直接回收Direct Reclaim导致进程阻塞——这是生产环境延迟尖峰latency spike的主要元凶。OOM Killer 策略/proc/sys/vm/oom_kill_allocating_task0扫描所有进程选择 oom_score 最高者默认1直接杀死触发 OOM 的进程减少扫描开销我们可以通过调整权重来保护关键进程# 保护MySQL进程echo-1000/proc/$(pgrep mysqld)/oom_score_adj四大核心机制详解Page CachePage Cache是Linux内存管理中最智能的部分之一它通过缓存磁盘数据来提升系统性能。这也是为什么我们经常看到服务器内存使用率很高但系统依然正常运行的原因。SwapSwap空间是磁盘上的一块区域当物理内存不足时内核会将不常用的内存页换出到Swap。然而在现代生产环境中对于数据库服务器禁用Swap是常见做法因为磁盘I/O速度远慢于内存对于应用服务器保留少量Swap如4GB作为缓冲避免直接被OOM Killer杀死进程透明大页THP# 查看THP状态cat/sys/kernel/mm/transparent_hugepage/enabled[always]madvise never# 输出 [always] 表示全局开启THP可以减少TLB缺失提升大内存应用的性能但可能导致内存碎片和延迟波动。生产环境建议# 调整为madvise让应用自己决定echomadvise/sys/kernel/mm/transparent_hugepage/enabled推荐关闭 THP 的场景延迟敏感型数据库/大数据服务典型应用Oracle、MySQL、PostgreSQL、Redis、Doris、Elasticsearch 等。原因THP 的后台守护进程 khugepaged 会频繁扫描并合并小页导致不可预测的 CPU 峰值和内存锁竞争引发查询延迟抖动微秒至毫秒级。内存碎片化严重时THP 可能触发激进的直接内存回收Direct Compaction造成性能骤降甚至服务超时。可开启 THP 的场景通用计算负载典型场景Web 服务器、文件服务、开发环境等内存访问模式较均匀的应用。优势自动提升 TLB 命中率减少页表项开销无需应用修改即可获得性能收益。永久关闭推荐在/etc/default/grub的GRUB_CMDLINE_LINUX追加transparent_hugepagenever执行update-grub reboot。验证效果grepAnonHugePages /proc/pid/smaps# 若输出全 0 表示 THP 已禁用OOM Killer残酷的生存游戏当系统真正内存不足时OOM Killer会根据每个进程的oom_score选择“牺牲者”。合理配置进程的oom_score_adj可以保护关键服务。# 保护MySQL进程echo-1000/proc/$(pgrep mysqld)/oom_score_adjCgroups v2云原生时代的资源管控标准从 v1 到 v2 的范式转移Cgroups v2 采用统一层级结构Unified Hierarchy解决了 v1 中多个子系统独立挂载的复杂性。目前 Ubuntu 22.04、RHEL 9、Fedora 31 已默认启用。特性Cgroups v1Cgroups v2层级结构多层级各控制器独立单一层级统一管控进程归属可属于不同层级的不同组只能属于一个 cgroup内存控制memory.limit_in_bytesmemory.max硬限制设备控制直接配置基于 eBPF 实现PSI 支持无原生支持内存控制模型Cgroups v2 引入精细化的内存控制策略类似水库的三级闸门memory.low软保护最佳努力保护内核优先回收其他 cgroup 内存Kubernetes Guaranteed QoS Pod 的底层实现memory.high节流阀超过此值内核启动激进回收进程进入节流状态生产陷阱应用在 OOM 前可能已因memory.high节流而性能暴跌但监控往往只关注 OOMmemory.max硬限制绝对上限触发 OOM Killer生产配置示例配置仅供参考实际情况是需要根据自己服务器配置情况进行修改。# 创建生产级 cgroupmkdir-p/sys/fs/cgroup/prod-api# 启用内存控制器echomemory/sys/fs/cgroup/cgroup.subtree_control# 设置三级闸门单位字节echo8589934592/sys/fs/cgroup/prod-api/memory.low# 8GB 保护echo12884901888/sys/fs/cgroup/prod-api/memory.high# 12GB 开始节流echo17179869184/sys/fs/cgroup/prod-api/memory.max# 16GB 硬限制# 迁移进程echoPID/sys/fs/cgroup/prod-api/cgroup.procs# 监控实时压力cat/sys/fs/cgroup/prod-api/memory.pressurePSI 量化资源压力的利器Pressure Stall InformationPSI是Linux 内核版本 4.20引入的精确压力度量机制提供墙钟时间占比而非简单的计数器。PSI 核心指标解读cat/sys/fs/cgroup/prod-api/memory.pressure# 如果提示没有这个文件请看下面的开启方法# some avg100.12 avg600.34 avg3001.23 total12345678# full avg100.00 avg600.01 avg3000.05 total987654some至少一个任务因内存等待停滞的时间占比0 即表示存在节流full所有任务同时停滞的时间占比预示 OOM 风险生产告警阈值建议some avg60 5%黄色预警存在内存压力some avg60 20%红色告警严重节流full avg10 1%紧急状态 imminent OOM启用 PSIgrubby --update-kernelALL--argspsi1reboot激活cgroup控制器‌# 在根cgroup启用控制器echomemory io cpu|sudotee/sys/fs/cgroup/cgroup.subtree_control# 在目标cgroup启用控制器如prod-apimkdir-p/sys/fs/cgroup/prod-apiechomemory io cpu|sudotee/sys/fs/cgroup/prod-api/cgroup.subtree_control# 验证控制器状态cat/sys/fs/cgroup/prod-api/cgroup.controllers# 应包含memory/io/cpu再次查看即可# 应正常输出压力数据cat/sys/fs/cgroup/prod-api/memory.pressure# 示例输出avg100.00 avg600.00 avg3000.00 total0与 Kubernetes 的集成Kubernetes 依赖 kubelet 监控 PSI 实现主动驱逐Eviction在节点级内存压力时优先驱逐 BestEffort/Burstable Pod避免触发系统级 OOM Killer 导致关键服务随机死亡eBPF 内存监控的终极武器内核级内存追踪eBPF 允许在内核态安全执行自定义代码实现亚微秒级的内存事件追踪且几乎无性能损耗。典型应用场景追踪malloc/free调用栈定位内存泄漏监控 Slab 分配器碎片化统计 Page Cache 命中率BPF Map 内存管控要点从 Cgroups v2 开始BPF Map 占用的内核内存被正确计入 cgroup 账户。这对使用 eBPF 的监控/安全工具如 Cilium、Falco至关重要命令安装Ubuntu/Debianaptinstalllinux-tools-$(uname-r)CentOS/RHEL/Alibaba Cloud Linux‌yum-yinstallbpftool# 查看 BPF Map 内存占用需 rootbpftool map-j|jq[ .[] | .bytes_memlock ] | add / 1024 / 1024# 输出总占用 MB 数# 按进程聚合bpftool map-j|jqgroup_by(.pids[0].comm) | map({comm: .[0].pids[0].comm, total_mb: (map(.bytes_memlock) | add / 1024 / 1024)}) | sort_by(.total_mb)生产建议未使用的 Map 应设置max_entries1并在加载时动态调整避免空 Map 占用大量锁定内存locked memory。生产环境最佳实践监控看对指标才是关键不要只看used内存更应该关注可用内存available字段包含可回收的CacheSwap使用率即使有Swap使用率也不应持续高于10%页面交换siswap in和soswap out次数PSI指标监控内存压力的真实情况$vmstat1procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpdfreebuff cache si so bi boincs us syidwa st2001234567891011131415160000001058500参数调优因“应用”制宜在/etc/sysctl.conf中根据应用类型调整内存敏感型应用如Redis# 降低swap使用倾向vm.swappiness1# 尽早触发内存回收vm.vfs_cache_pressure200文件服务器# 保留更多Cachevm.vfs_cache_pressure50# 允许更多脏页vm.dirty_ratio40vm.dirty_background_ratio10容器化部署 checklist强制使用 Cgroups v2# 检查当前版本stat-fc%T /sys/fs/cgroup/# 应输出cgroup2fs合理设置memory.high设置为memory.limit的 90%提前触发节流而非 OOMJava/Go 应用需结合 GC 调优避免与内核回收冲突启用 PSI 监控部署 node-exporter 1.3.0 采集 PSI 指标Grafana 配置rate(node_pressure_memory_waiting_seconds_total[1m])告警Kubernetes 环境配置apiVersion:v1kind:Podspec:containers:-name:appresources:requests:memory:512Mi# 调度依据limits:memory:1Gi# 超过此值会被OOM Kill设置合理的requests和limits启用kubelet的--kernel-memcg-notification特性及时回收内存大页内存HugePages优化对于数据库MySQL/PostgreSQL和内存型缓存Redis# 查看当前大页配置cat/proc/sys/vm/nr_hugepages# 动态分配 1024 个 2MB 大页echo1024/proc/sys/vm/nr_hugepages# 在 cgroup v2 中限制 HugeTLB 使用echo1073741824/sys/fs/cgroup/prod-api/hugetlb.2MB.max故障排查三板斧场景应用响应变慢怀疑内存问题快速查看内存概况grep-iout of memory/var/log/messagesdmesg|grep-ikilled process分析具体进程# 查看内存使用前10的进程psaux--sort-%mem|head-11# 查看/proc中进程的详细内存信息cat/proc/PID/smaps|grep-ipss深入内核状态slabtopcat/proc/meminfocat/proc/buddyinfo# 查看内存碎片情况危险操作警示避免在生产环境直接执行echo3/proc/sys/vm/drop_caches# 强制清理缓存这会导致瞬间 I/O 风暴应通过调整memory.high让内核渐进式回收。从LRU到Memory TieringMemory Tiering内存分层管理随着Intel Optane等非易失性内存的出现Linux内核正在发展Memory Tiering机制。这种机制可以自动将“热”数据放在快速内存如DRAM将“冷”数据移到慢速内存如CXL内存实现性价比的最优化。总结现代 Linux 内存管理已从简单的分配-回收演进为多层次资源管控体系层级技术适用场景内核机制Buddy/Slab/回收算法物理资源管理资源隔离Cgroups v2多租户/容器化压力感知PSI预测性扩缩容可观测性eBPF精细化故障诊断Linux内存管理是一个动态、智能的系统。在生产环境中我们应当理解机制区分真正的内存不足与Page Cache占用监控正确指标重点关注available内存、Swap活动和PSI压力因应用配置不同工作负载需要不同的内核参数和cgroup设置预防优于救治设置合理的监控阈值和告警规则拥抱新技术积极采用Cgroups v2、PSI和eBPF等现代工具本文技术细节基于 Linux 6.x 内核适用于 RHEL 9、Ubuntu 22.04/24.04、Containerd 1.7 等主流生产环境。希望这篇文章能帮助你更好地理解和管理服务器内存。如果你有特殊的内存管理案例或经验欢迎在评论区分享讨论

更多文章