项目场景:
一位学生有一台笔记本电脑,安装了Android,Kafka虚拟机很多软件。笔记本配置了20GB内存,固态硬盘,但最近很卡,Android Stuido经常闪退,一些游戏也无法运行。最近因为其他计算机损坏,需要临时借用这个笔记本作为kafka虚拟机的宿主,通过USB连接一个NAS实现服务,不得不马上解决这个问题。
最终,通过 sysinternals::Rammap64 工具集,分析了内存占用,并采用任务计划和定期清理功能保证系统健康。
问题描述
由于Android Studio是很耗内存的软件,首先想到观察内存,发现可用内存不足5%,资源监视器大量“硬中断”报警,说明存在大量的内存分配失败。同时页面缓存也涨到快10GB,更说明是内存不够了。这直接导致开启一些大型3D游戏时卡顿(大量的Page交换),安卓仿真器崩溃。使用进程工具统计所有进程的内存,发现总共才占了6GB不到,那另外12GB内存是谁占用了?
(下图来自类似故障的网站)
初步排查:
考虑到同学启动了一个debain的虚拟机作为一个本地服务器,测试一些新版本Kafka的功能。会不会是虚拟机的问题呢? 同学也说本来以为是的,但是把虚拟机的内存从8G下降到2GB,还是会内存爆满。
在现场,我再次终止虚拟机后,内存果然全部释放干净了。但这个虚拟机总共才2GB的内存配置,怎么可能占用如此多的内存呢?
我们试着复现现象:
- 重启笔记本,不启动虚拟机时,一切正常。
- 启动虚拟机,开启数据吞吐测试程序。这个程序会不断从虚拟机内存里吞吐大量的数据。
- 资源管理器发现内存缓慢涨大,并轻松突破了2GB的限制,持续膨胀。
- 最终内存全部用光,故障浮现。
这难道是虚拟机本身有内存泄露?由于几次测试,观察到除了正常的系统占用,内存增量基本是16GB左右就不再涨大,狐疑这个16GB是怎么回事。如果是软件故障,应该不会有上限,至少应该把页面文件都撑爆了再退出。但这个现象是由虚拟机占用的内存到达16GB就停止增长了。此时,若不运行别的软件,系统还是正常的。
抱着试一试的态度,在虚拟机设置页面瞎点,改了一堆参数,也没有用。结果,即将黔驴技穷的时候,在虚拟机的“全局配置”选项菜单里,有一个“预留内存”的选项,恰好是16GB多。
把这个预留内存下移到4GB,问题似乎解决了。但是,笔记本临时开机10天后,同学找到我,说一旦IO持续保持高位,内存还是会爆满。
解决方案:
经过近1个月的寻找,终于找到了一个神贴,使用工具 RAMMap 查看占用,发现是 VMWare 锁定了大量的空闲内存,并建立了到大量Kafka磁盘文件的mmap。这些内存被标记为Active,无法释放。
(下图来自上文的神贴,场景和本次运维场景很像)
这个RAMMap是Windows 内部工具集的一部分,,这个工具可以使用命令行:
C:\> RAMMap64 -Ew
C:\> RAMMap64 -Es
来释放占用的空间,效果很好。因此,只要在计划任务里每N时运行一次,基本可以保证运行畅通。
可能技术背景解释(可能是错误的)
不是很熟悉这款软件,但有个猜测:
- 这个“预留内存”应该是指由虚拟机统管的全部内存。
- 虽然客户OS只有 2GB内存,但因为IO频繁,虚拟机软件为避免碎片化,会用所有的16GB预留内存来周转数据。
- 增长期,随着频繁的IO,内存不断涨大。2GB客户机里的new每次都在宿主的这16GB缓存的尾部新增长,而不是重用2GB的空间。
- 稳定期,16GB空间用完,回到头部去找新的空闲位置。
上图中,虽然蓝色的虚拟机2GB内存大小不变,但是在虚拟机预留内存中的位置却时刻变化,并逐步遍历了所有的预留内存。因此,这个“预留内存”如果不是专门用来跑虚机的电脑,千万不要设置太大。如果要吃鸡或者GTA,应该非常谨慎地设置内存。
当遇到极端情况,比如本次,让一个笔记本承载极高的KafkaIO的虚拟化,则会导致系统来不及释放内存。
RAMMAP各类内存的解释
原文:
Glossary and Guide to the column and row headings
Stages of memory
Active: Pages of physical RAM in active use by the specified category (usually a process working set or the system working set).
Standby: Pages of physical RAM not actively being used. These are still left in physical RAM but will be repurposed first by the memory manager (either returned to the active list or zeroed out and reused) if something needs physical ram for active pages.
Modified: Similar to Standby, but these are pages of physical RAM that have been changed and must be flushed to disk before reusing them.
Modified no write: Similar to modified pages but have been marked not to write out to disk.
Transition: Pages that are in transition between any of the other categories
Zeroed: Pages that have been zeroed out and are ready to be used – they can be quickly allocated for new physical memory allocations
Free: Free pages are free to be used but have some type of “dirty” data in them so they must be zeroed for security reasons before given to a user process. These are usually pages that have been freed by an existing process.
Bad: These are physical pages that have been marked as bad.
Areas of interest would be the following rows to check for high memory consumption to account where the rest of your memory is being used.
TIP:
If you have a memory leak and get to the point of almost running out of memory, the normal procedure is to reboot the machine in order to clear out the memory. You can use RAMMap to clear areas of memory negating the need to reboot the machine.
RAMMAP列出的内存包括:
- 活动:指定类别(通常是进程工作集或系统工作集)正在使用的物理RAM页面。
- 待机:物理RAM的页面没有被主动使用。这些仍然留在物理RAM中,但如果活动页面需要物理RAM,内存管理器将首先重新调整用途(要么返回到活动列表,要么清零并重复使用)。
- 修改:类似于IO缓存,但这些是物理RAM的页面,已更改,必须先刷新到磁盘,然后才能重新使用。
- 修改后不写入:类似于修改后的页面,但已标记为不写入磁盘。
- 转换:在任何其他类别之间转换的页面
- 归零:已归零并准备使用的页面–它们可以快速分配给新的物理内存分配
- 空闲:空闲页面可以立刻使用,但其中有某种类型的“脏”数据,因此出于安全原因,在将其提供给用户进程之前,必须将其归零。这些通常是由现有进程释放的页面。
- 损坏:这些是被标记为坏的物理页面。
提示:
如果内存泄漏,并且几乎耗尽内存,正常程序是重新启动机器以清除内存。您可以使用RAMMap清除内存区域,从而无需重新启动机器。