服务器内存不断增长,是每个运维和后端工程师都会遇到的问题。本文记录一次完整的内存排查过程,从发现问题到定位根因。
top 与 ps 基础命令
top 命令
1 | top |
输出:
1 | top - 10:30:00 up 50 days, 3:22, 2 users, load average: 0.52, 0.48, 0.45 |
关键字段:
- VIRT:虚拟内存总量
- RES:实际占用的物理内存(常驻内存 RSS)
- SHR:共享内存
- %MEM:内存占用百分比
ps 命令
1 | # 查看内存占用最高的进程 |
常用组合
1 | # 实时监控内存 |
/proc 内存分析
Linux 的 /proc 目录包含内核和进程的信息。
查看进程内存映射
1 | # 进程内存映射 |
输出示例:
1 | 00400000-00452000 r-xp 00000000 fd:00 123456 /path/to/executable |
查看内存详情
1 | # 内存状态(单位 pages) |
查看 OOM 杀掉的进程
1 | # 系统日志中的 OOM |
内存类型解析
Linux 内存分为多种类型,理解它们有助于定位问题。
内存类型说明
| 类型 | 说明 | 正常值 |
|---|---|---|
| VIRT | 虚拟内存 | 可大于物理内存 |
| RES | 常驻内存 | 应接近实际使用 |
| SHR | 共享内存 | 多进程共享库 |
| Data | 数据段 | 堆 + 栈 + 数据 |
查看内存分布
1 | # 内存总量和空闲 |
buff/cache 区别
1 | # Buffers: 块设备(磁盘块)的缓存 |
判断是否真的内存不足
1 | # 如果 available 远大于 free,说明内存被缓存占用 |
缓存与缓冲区别
page cache(页缓存)
页缓存是内存中存储文件数据的地方:
1 | # 查看页缓存 |
swap 使用分析
1 | # 查看 swap 使用 |
监控 swap 活动
1 | # 查看 swap in/out |
判断内存泄漏
1 | # 观察内存使用趋势 |
实战:定位内存泄漏进程
步骤1:确认问题
1 | # 查看整体内存 |
步骤2:找出占用最高的进程
1 | ps aux --sort=-%mem | head -20 |
1 | USER PID %MEM RSS |
步骤3:分析具体进程
1 | # 查看 Java 进程的内存映射 |
步骤4:如果是 MySQL
1 | # 查看 MySQL 内存使用 |
步骤5:如果是 Java
1 | # 查看 JVM 堆外内存 |
步骤6:如果是 Python
1 | # Python 内存泄漏 |
步骤7:定位泄漏代码
1 | # 使用 strace 追踪内存分配(慎用,会很慢) |
常见问题与解决
问题1:Java 堆外内存泄漏
1 | # JVM 参数限制 |
问题2:Nginx 内存泄漏
1 | # 限制 worker 进程 |
问题3:Python 内存持续增长
1 | # 使用弱引用 |
问题4:MySQL 临时表占用过多内存
1 | -- 限制临时表大小 |
总结
Linux 内存排查流程:
- 观察整体:
free -h、top - 定位进程:
ps aux --sort=-%mem | head - 分析进程:
/proc/<pid>/status、pmap - 判断类型:堆、堆外、缓存、swap
- 定位根因:代码、配置、JVM 参数
- 解决:修复代码或调整配置
关键命令速查:
| 命令 | 用途 |
|---|---|
free -h |
内存概览 |
top |
实时监控 |
ps aux --sort=-%mem |
按内存排序进程 |
cat /proc/meminfo |
详细内存信息 |
vmstat 1 |
内存和 swap 活动 |
pmap -x <pid> |
进程内存映射 |
dmesg | grep -i oom |
OOM 日志 |