第90课 - 内存管理与调优
学习目标
完成本课学习后,你将能够:
- 理解Linux内存分配的核心机制(如页面缓存、匿名页面、OOM Killer)
- 诊断常见的内存使用问题,区分正常缓存与内存泄漏
- 掌握使用工具监控内存状态、分析内存瓶颈的方法
- 应用内存调优策略(如调整swappiness、配置OOM Killer、使用透明大页)
核心概念
1. Linux如何高效使用内存?
Linux不会让宝贵的内存闲置。它主要用两种方式“物尽其用”:
- 页面缓存:系统把读过的磁盘文件内容缓存到内存中。下次再读同一个文件,就直接从内存取,速度飞快。这就是为什么
free命令显示buff/cache很高是正常且高效的表现。 - 匿名页面:程序运行时申请的内存(如变量、堆栈),这部分数据没有对应的文件,称为匿名页面。
当系统需要更多内存时,内核会优先丢弃一些不再使用的页面缓存,为急需内存的程序腾出空间。只有当所有缓存都已释放仍不够用时,才会考虑使用swap。
2. OOM Killer:内存不足的“终极裁判”
当物理内存和swap空间都被耗尽,内核会激活OOM Killer。它的任务是找出并“杀掉”一个或多个占用内存最多、最不重要的进程,以释放内存,避免系统完全卡死。
- 重要性评分:每个进程都有一个
oom_score(/proc/<PID>/oom_score),分值越高,越容易被选中。你可以通过/proc/<PID>/oom_score_adj(范围-1000到1000)手动调整这个评分。 - 策略:生产环境中,通常将关键业务进程(如数据库)的
oom_score_adj设为负值,降低其被误杀的风险。
3. Swap空间:内存的延伸,也是性能的权衡
Swap是磁盘上的一块空间,当物理内存紧张时,内核会将不活跃的内存页交换到Swap中。这能防止进程因内存不足而立即崩溃。
- 过度依赖Swap的代价:磁盘速度比内存慢几个数量级。频繁的Swap交换(称为“颠簸”)会导致系统响应极其缓慢。
- swappiness参数:这是个0-100的值,控制内核将内存页交换到Swap的积极程度。
0:尽量避免使用Swap,直到绝对必要。100:积极使用Swap。- 服务器推荐设置较低值(如10-30),以优先保留缓存。
4. 高级特性
- 透明大页:普通内存页大小为4KB,大页为2MB或1GB。使用大页可以减少内存管理开销,提升大内存应用(如数据库、虚拟机)的性能。但THP可能会引起延迟抖动,需要根据应用特性选择是否启用。
- 内存压缩:内核可以将不常用的内存页压缩后存放在内存中,而不是交换到慢速磁盘,这是一种用CPU时间换内存空间的策略。
代码示例
示例1:实时监控内存状态
#!/bin/bash
# 实时监控内存和Swap使用情况
echo "=== 基础内存信息 (free -h) ==="
free -h
echo ""
echo "=== 详细内存信息 (从/proc/meminfo提取关键项) ==="
grep -E 'MemTotal|MemFree|MemAvailable|Buffers|Cached|SwapTotal|SwapFree|Dirty|Writeback' /proc/meminfo
echo ""
echo "=== 实时内存活动监控 (vmstat 1 5) ==="
# 字段说明:
# si (swap in): 从磁盘换入内存的量 (KB/s)
# so (swap out): 从内存换出到磁盘的量 (KB/s)
# free: 空闲内存量
# buff: 缓冲区缓存
# cache: 页面缓存
vmstat 1 5
示例2:诊断内存压力与OOM事件
#!/bin/bash
# 检查系统是否经历过OOM以及近期内存压力
echo "=== 检查内核OOM Killer日志 ==="
# dmesg中的oom-killer条目
dmesg | grep -i "out of memory" | tail -5
echo ""
echo "=== 查看系统内存压力指标 (从/proc/vmstat) ==="
# oom_kill: 被OOM Killer杀掉的进程总数
# pgsteal_*: 内核为获取内存而从缓存/匿名页面中回收的页面数
# pswpin/pswpout: swap交换的页面总数
grep -E 'oom_kill|pgsteal|pswpin|pswpout' /proc/vmstat
echo ""
echo "=== 找出当前最占内存的10个进程 (按RSS排序) ==="
# RSS (Resident Set Size): 进程实际占用的物理内存大小
ps aux --sort=-%mem | head -11
示例3:内存调优参数查看与调整
#!/bin/bash
# 查看并解释关键内存调优参数
echo "=== 当前Swap使用倾向 (swappiness) ==="
cat /proc/sys/vm/swappiness
# 立即修改(临时,重启失效): sysctl vm.swappiness=10
echo ""
echo "=== 当前缓存清理倾向 (vfs_cache_pressure) ==="
# 该值越高,内核越倾向于回收用于目录和inode对象的缓存。
cat /proc/sys/vm/vfs_cache_pressure
echo ""
echo "=== 透明大页状态 ==="
cat /sys/kernel/mm/transparent_hugepage/enabled
# 输出示例:[always] madvise never
echo ""
echo "=== 使用tuned-adm检查/应用优化配置 ==="
# tuned是一个自动调优守护进程,可根据profile自动优化系统。
tuned-adm active
# 列出所有可用profile:tuned-adm list
# 应用一个优化内存的profile:tuned-adm profile virtual-guest
实践练习
练习1:内存使用分析(初级)
- 在你的Linux系统上运行
free -h和vmstat 1 3。 - 回答以下问题:
- 系统的
MemAvailable是多少?它代表什么含义? si和so列是否持续大于0?这可能说明什么问题?- 结合
buff/cache和used值,评估当前内存是否紧张。
- 系统的
- 预期输出:一份简短的分析报告,指出系统当前的内存状态。
练习2:Swap优先级调整(中级)
- 当前系统有两个swap分区/文件。使用
swapon --show查看它们。 - 当前它们的优先级可能相同。尝试修改其中一个的优先级,使得系统优先使用速度更快的那个。
- 提示:
sudo swapon --priority 10 /dev/sdXN或修改/etc/fstab中的pri=参数。
- 提示:
- 使用
free -h和vmstat观察调整后,系统是否仍会使用低优先级swap。 - 预期输出:调整后的swap状态以及观察结果。
练习3:模拟与应对OOM(高级)
- 警告:此操作会消耗大量内存,请在测试环境中进行!
- 创建一个简单的Python脚本
memory_eater.py,它逐步申请内存:import time chunks = [] try: while True: chunks.append(' ' * 1024 * 1024) # 每次申请1MB print(f"已申请 {len(chunks)}MB 内存") time.sleep(0.1) except MemoryError: print("申请内存失败,系统可能已触发OOM或进程被杀死") - 在另一个终端,监控内存和OOM日志:
watch -n 1 free -h和tail -f /var/log/syslog | grep -i oom。 - 运行脚本
python3 memory_eater.py,观察当内存耗尽时会发生什么。 - 尝试在运行前,将该进程的
oom_score_adj设置为一个极高的值(如1000),观察它是否更容易被OOM Killer选中。 - 预期输出:描述从内存耗尽到进程被杀的全过程,并解释日志中的关键信息。
常见错误
-
误将“高缓存”视为“内存不足”
- 错误认知:看到
free命令中buff/cache占用很高,就认为内存不足。 - 正确理解:高缓存是好事!关注的重点应该是
available列,它表示系统可用内存(包括可回收的缓存)。
- 错误认知:看到
-
忽视OOM Killer日志
- 错误:服务突然停止,却只检查应用日志。
- 正确:服务异常终止时,务必使用
dmesg | grep -i oom检查内核日志,确认是否为内存耗尽所杀。
-
盲目禁用Swap
- 错误:为了追求“全内存”性能而完全关闭Swap。
- 正确:保留适量Swap作为安全缓冲是必要的。完全无Swap的系统在突发内存高峰时更容易触发OOM,导致关键服务崩溃。
-
swappiness设置为0的误解
- 错误:认为
swappiness=0就完全不使用Swap。 - 正确:当内核
vm.swappiness=0时,它仍然会在绝对必要时使用Swap以防止OOM。只是回收匿名页面的倾向性极低。
- 错误:认为
-
调整THP不考虑应用特性
- 错误:对所有系统都启用或禁用透明大页。
- 正确:THP对数据库、虚拟机等大内存应用有显著收益,但也可能导致延迟尖峰。需要根据应用文档和性能测试结果来决定是否启用。
小结
本课深入探讨了Linux内存管理的内在逻辑与调优实践:
- 核心机制:理解了Linux通过页面缓存和匿名页面高效利用内存,以及当内存耗尽时OOM Killer的运行原理。
- 监控诊断:掌握了使用
free、vmstat、/proc/meminfo和系统日志来诊断内存状态、区分缓存占用与内存压力、追溯OOM事件。 - 关键参数:学会了通过调整
swappiness来平衡性能与稳定性,通过设置oom_score_adj来保护关键服务。 - 进阶调优:了解了透明大页和内存压缩等高级特性及其适用场景。
记忆要点:不要害怕free里的高缓存数字,它说明系统在高效工作。真正的内存问题在于available持续走低,并伴随swap活动频繁或oom_kill事件。调优的目标是在性能和稳定性之间找到最佳平衡点。
练习编辑器
rust
Loading...