返回列表 发布新帖
查看: 6|回复: 0

什么是僵尸内存?(Zombie Memory)

发表于 昨天 16:45 | 查看全部 |阅读模式

这里或许是互联网从业者的最后一片净土,随客社区期待您的加入!

您需要 登录 才可以下载或查看,没有账号?立即注册

×
在服务器运维、应用部署或系统性能优化过程中,我们经常会听到一个概念——僵尸内存(Zombie Memory)。虽然“僵尸进程”这个词比较常见,但“僵尸内存”却经常让人误以为是 Linux 系统的一种结构。实际上,僵尸内存并不是 Linux 的正式概念,而是运维人员为了描述异常占用却无法释放的内存而使用的俗称。
本文将带你理解什么是僵尸内存、为什么会出现、如何诊断以及如何修复。
一、僵尸内存的定义
僵尸内存(Zombie Memory)指的是:
被应用程序占用,但由于程序 Bug 或系统异常,已经无法正常释放的内存。即使进程已结束或不再使用这些内存,它们仍被系统标记为“已使用”,无法再次分配。
这种状态会导致:
  • 可用内存越来越少
  • 系统变慢甚至 OOM(Out Of Memory)
  • 某些程序频繁被系统杀死(例如 mysqld、java 等占内存应用)
二、僵尸内存的常见表现
出现僵尸内存时,你可能看到如下现象:
1. free -m 显示“已用内存”不断增加,但没有对应进程在占用
  1. free -m
复制代码
看到:
  • used 一直涨
  • buff/cache 没什么变化
  • 但 top、htop 又找不到占内存的进程
2. OOM Killer 频繁触发
在 /var/log/messages 或 dmesg 中看到:
Out of memory: Kill process xxx (mysqld) score 987
3. 程序明明已经退出,但占用的内存仍未释放
例如 java 崩溃后仍占用大量内存块。
三、导致僵尸内存的根本原因
僵尸内存通常由以下问题引起:
1. 程序内存泄漏(Memory Leak)
最常见原因。
某些程序申请了内存但没有正确释放,导致:
  • 该进程占用的内存持续增长
  • 内存碎片化
  • 内存在进程退出后仍没有正常释放
常发生在:
  • C/C++ 程序
  • 自定义模块
  • 第三方插件
  • 长期运行的守护进程(Nginx 模块、PHP-FPM、老版本 Java 应用等)
2. Kernel 内存泄漏(通常来自驱动或内核模块)
典型特征:
  • top 查不到占用大量内存的进程
  • slab 占用巨大
查看 slab:
  1. slabtop
复制代码
常见触发源:
  • 错误的网卡驱动
  • 文件系统 Bug
  • Docker overlayfs 泄漏
  • 高速网络 + 某些内核版本的内存管理 Bug
  • 长时间运行未重启的系统
3. 文件被进程删除但仍占用内存(tmpfs / pagecache)
例如:
  • 日志文件过大
  • 程序执行时删除了文件句柄
  • 内存中的文件句柄仍被占用
查看:
  1. lsof | grep deleted
复制代码
如果看到大量:
  1. /var/log/app.log (deleted)
复制代码
说明该文件本体删了,但程序仍在占着内存。
4. Docker、K8s 容器造成的内存异常
容器系统中的常见问题:
  • 容器内内存泄漏
  • overlay2 缓存泄漏
  • 容器退出后 Cgroup 未释放资源
查看:
  1. docker stats
复制代码
5. 大量 Page Cache 未及时回收
当执行大量文件 I/O 后,系统会缓存文件内容。
如果未及时回收,看起来像内存被“吃掉”。
四、如何诊断僵尸内存?(重点)
1. 查进程内存占用
  1. top
复制代码
  1. ps aux --sort=-rss | head
复制代码
2. 查看 Slab 内存是否异常
  1. slabtop
复制代码
  1. grep -i slab /proc/meminfo
复制代码
如果 slab 很大(例如几十GB),通常是内核泄漏。
3. 查找被删除但仍占用的文件
  1. lsof | grep deleted
复制代码
4. 检查 docker/kubernetes 内存占用
  1. docker stats
复制代码
  1. cat /sys/fs/cgroup/memory/memory.usage_in_bytes
复制代码
5. 检查 pagecache
  1. cat /proc/meminfo | grep -i cache
复制代码
五、如何修复僵尸内存?
1. 重启对应服务
例如:
systemctl restart php-fpm
systemctl restart nginx
systemctl restart docker
通常能释放进程泄漏的内存。
2. 清理 pagecache(安全)
  1. sync; echo 3 > /proc/sys/vm/drop_caches
复制代码
3. 重启 Docker 或 K8s 节点
处理容器造成的内存泄漏:
  1. systemctl restart docker
复制代码
4. 更新内核或驱动
如果 slab 异常巨大,多半是内核泄漏。
升级内核通常可以解决。
5. 对应用进行内存泄漏排查
使用:
  • valgrind
  • pmap
  • strace
  • heapdump(JAVA)
  • php-fpm slowlog
6. 最后手段:重启系统
当内核级别的泄漏导致内存无法回收时,只能通过系统重启解决。
六、如何预防僵尸内存?
  • 使用稳定版本的内核与驱动
  • 定期重启高风险程序(守护进程)
  • 有限制地使用第三方模块
  • 对 C/C++ 程序做 valgrind 测试
  • 监控内存增长趋势(Prometheus + Grafana)
  • 配置 OOM 保护策略
总结
僵尸内存不是操作系统正式术语,而是指:
由于程序或系统漏洞导致无法被正常释放的内存,逐渐侵蚀系统可用资源,使系统变得缓慢甚至崩溃。
它可能来自:
  • 应用内存泄漏
  • 内核泄漏
  • 文件句柄未释放
  • Docker/K8s 问题
  • PageCache 堆积
通过系统监控、日志分析以及对特定模块排查,可以有效避免僵尸内存问题,保持系统稳定运行。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Copyright © 2001-2025 Suike Tech All Rights Reserved. 随客交流社区 (备案号:津ICP备19010126号) |Processed in 0.128091 second(s), 7 queries , Gzip On, MemCached On.
关灯 在本版发帖返回顶部
快速回复 返回顶部 返回列表