我的办公电脑一直有个莫名其妙的问题,那就是随着开机时间变长和日常工作的进行,物理内存占用越来越高,但是任务管理器里的数字和每个进程的数字加起来对不上。
按进程求和的数字小得多,Windows莫名其妙在一口一口吃掉我本来就不多的物理内存?
0x00. 事件起因
因为确实有很多服务要在办公电脑上跑(别问为什么,我也不想),所以我把办公电脑的内存加到了24G(8+16),这样分出7个G来跑三个虚拟机,剩下17G用作日常使用。我本来觉得,这样的配置应该和家里的16G用起来类似,但我没有预料到的是,家里的电脑跑一天下来内存占用是没什么变化的,办公电脑的内存占用却在一个劲的往上涨。
一般来说,是个人都猜到了这叫内存泄漏,而且,也是一般来说,看到是哪个进程占了太多内存,噶了它重启就完事了,甚至可以写个脚本去自动噶,这都不是事儿。
但尴尬的是,没有哪个进程占了太多内存,更尴尬的是,进程的内存加一起根本没有占用这么多?
0x01. 我的内存呢?
一般来说,这时候就该打开RAMMap了:
打个比方,这是我现在(正在全盘扫描病毒,我也不知道为什么我们的杀软要在上班时间自动扫全盘,大概是吃得太饱)的内存占用,可以看出,各类进程占了5G,然后往内存里放了4G的文件(Mapped File),还有剩下的一些blahblahblah。问题不大,点一下Empty就能把Mapped File给扔到Standby里面去,就不算占用内存了。
而我实际上碰到的问题是,Page Table占用高得超乎想象,借用一下另一个帖子的图:
这个Page Table就尴尬了,大致意思就是,是个进程都要用内存,但是内存地址是虚拟出来的,所以要有个速查表才能到物理内存的真实位置上,根据每个进程占用内存的不同,这个表大小也会变化,但是一般来说这个数字不应该超过一两百兆——因为一般来说,进程退出了之后,这个表就自动销毁了。
而且,这个数字这么大,在进程列表里看不出来,说明,占用它们的,不在进程列表里。Huh?
0x02. 这个情况不一般
因为Page Table这部分爆高说明我有超多进程开着,但这不可能,这台办公用破电脑会先炸掉,大概。
但我在任务管理器里确实发现了诡异的情况:
一般来说,进程ID是系统自动分配,而且是递增的,而且在Windows是4的倍数。如果我现在开了个程序,PID是299904,说明它搞不好是这次开机之后第七万多个开启的进程。
当然了,由于Windows可能也会回收PID:
这个回答真是自信得令人发指……
所以第七万多个都是保守估计……
我到底是怎么开了七万多个进程还没让电脑冒烟的?
还是在RAMMap这边,答案揭晓:
因为我在用脚本跑Selenium爬虫,图省事直接开了Chrome就关,然后在无数次地开启关闭后,它们全部僵尸化了。
0x03. 僵尸进程
这些chrome.exe和chromedriver.exe全部都已经退出了,但由于某种未知的原因,它们没有或者没法释放自己的某些资源,导致Page Table没有释放。但他们在Windows眼里已经死掉了,所以任务管理器看不到,taskkill也是无效的。它们已经死了,但是还从坟墓里伸出一只手来抓住了那么一丁点儿内存……
32k或者40k内存并不多,但几万个一起……
因为Windows没有僵尸进程(Zombie Process)一说,所以我也不知道用什么词语来形容它们比较好。但是它们的存在确确实实吃掉了我的内存……
0x04. 解决方法
对于由活着的进程导致的僵尸进程或线程,只要找到它们的父进程,噶掉就行了。brucedawson有一篇超赞的文章给了我很多启发而且提供了僵尸进程检测工具,当然对于我这种情况不好使,但依然是很有参考价值的。
工具明确检测出了有两万多的僵尸进程,但我这些死掉的进程,很遗憾地,已经不知道父进程死哪儿去了(此处应有meme),因为调用它们的python脚本早就退出,现在要么是0要么是4要么就没有父进程的概念,要么就是我还没找到方法,要么就是杀软(手工退掉还会有个告警,算了吧),总之,没法噶掉,所以解决方法只剩下了一个:重启。
没错,重启肯定完美解决问题,只要我不继续跑这个爬虫(或者改成一个浏览器进程跑到黑的模式)。
0x05. 总结
如果你也碰到类似的情况,最简单的方法是,在任务管理器里把“句柄”那列打开,然后降序排序,干掉句柄多到不正常的那个,这是最常见的僵尸进程,可以被噶掉的那种。
如果你不幸碰到我这种情况,重启。
如果你确实不想重启,还是得重启。不要再任性了。重启吧。喝杯茶看个报啥的。