90·系统监控与调优高级

内存管理与调优

memoryswaptuning

第90课 - 内存管理与调优

学习目标

完成本课学习后,你将能够:

  1. 理解Linux内存分配的核心机制(如页面缓存、匿名页面、OOM Killer)
  2. 诊断常见的内存使用问题,区分正常缓存与内存泄漏
  3. 掌握使用工具监控内存状态、分析内存瓶颈的方法
  4. 应用内存调优策略(如调整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:内存使用分析(初级)

  1. 在你的Linux系统上运行 free -hvmstat 1 3
  2. 回答以下问题:
    • 系统的MemAvailable是多少?它代表什么含义?
    • siso列是否持续大于0?这可能说明什么问题?
    • 结合buff/cacheused值,评估当前内存是否紧张。
  3. 预期输出:一份简短的分析报告,指出系统当前的内存状态。

练习2:Swap优先级调整(中级)

  1. 当前系统有两个swap分区/文件。使用 swapon --show 查看它们。
  2. 当前它们的优先级可能相同。尝试修改其中一个的优先级,使得系统优先使用速度更快的那个。
    • 提示:sudo swapon --priority 10 /dev/sdXN 或修改/etc/fstab中的pri=参数。
  3. 使用 free -hvmstat 观察调整后,系统是否仍会使用低优先级swap。
  4. 预期输出:调整后的swap状态以及观察结果。

练习3:模拟与应对OOM(高级)

  1. 警告:此操作会消耗大量内存,请在测试环境中进行!
  2. 创建一个简单的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或进程被杀死")
    
  3. 在另一个终端,监控内存和OOM日志:watch -n 1 free -htail -f /var/log/syslog | grep -i oom
  4. 运行脚本 python3 memory_eater.py,观察当内存耗尽时会发生什么。
  5. 尝试在运行前,将该进程的oom_score_adj设置为一个极高的值(如1000),观察它是否更容易被OOM Killer选中。
  6. 预期输出:描述从内存耗尽到进程被杀的全过程,并解释日志中的关键信息。

常见错误

  1. 误将“高缓存”视为“内存不足”

    • 错误认知:看到free命令中buff/cache占用很高,就认为内存不足。
    • 正确理解:高缓存是好事!关注的重点应该是available列,它表示系统可用内存(包括可回收的缓存)。
  2. 忽视OOM Killer日志

    • 错误:服务突然停止,却只检查应用日志。
    • 正确:服务异常终止时,务必使用 dmesg | grep -i oom 检查内核日志,确认是否为内存耗尽所杀。
  3. 盲目禁用Swap

    • 错误:为了追求“全内存”性能而完全关闭Swap。
    • 正确:保留适量Swap作为安全缓冲是必要的。完全无Swap的系统在突发内存高峰时更容易触发OOM,导致关键服务崩溃。
  4. swappiness设置为0的误解

    • 错误:认为swappiness=0就完全不使用Swap。
    • 正确:当内核vm.swappiness=0时,它仍然会在绝对必要时使用Swap以防止OOM。只是回收匿名页面的倾向性极低。
  5. 调整THP不考虑应用特性

    • 错误:对所有系统都启用或禁用透明大页。
    • 正确:THP对数据库、虚拟机等大内存应用有显著收益,但也可能导致延迟尖峰。需要根据应用文档和性能测试结果来决定是否启用。

小结

本课深入探讨了Linux内存管理的内在逻辑与调优实践:

  • 核心机制:理解了Linux通过页面缓存匿名页面高效利用内存,以及当内存耗尽时OOM Killer的运行原理。
  • 监控诊断:掌握了使用freevmstat/proc/meminfo和系统日志来诊断内存状态区分缓存占用与内存压力追溯OOM事件
  • 关键参数:学会了通过调整swappiness平衡性能与稳定性,通过设置oom_score_adj保护关键服务
  • 进阶调优:了解了透明大页内存压缩等高级特性及其适用场景。

记忆要点:不要害怕free里的高缓存数字,它说明系统在高效工作。真正的内存问题在于available持续走低,并伴随swap活动频繁或oom_kill事件。调优的目标是在性能和稳定性之间找到最佳平衡点。

练习编辑器

rust
Loading...

继续学习

完成本课后,建议继续学习下一课「SELinux 安全增强」 以巩固所学知识。