美文网首页程序员优化
记一次win10下的内存泄漏分析

记一次win10下的内存泄漏分析

作者: anyesu | 来源:发表于2018-08-20 17:38 被阅读768次

前言


在上回svn项目迁移到git的过程中遇到了内存泄漏的问题,本文就这个问题做一次分析和记录。

第一回合


之前对迁移过程做了大量测试,觉得都没问题了,就把项目带回家准备利用周末的时间来迁移,下周其他同事就可以正常提交代码而不用耽误太多时间了。

当然,回家后不会立即开始迁移,先做点正事。迁移的时候电脑应该专心点,免得出现什么未知问题,所以睡觉前开始挂机,醒来估计差不多就好了。嗯,想法很美好。

第二天起来,准备收割胜利的果实,结果发现电脑死机了(鼠标虽然还能动,但是点啥都没反应,键盘也毫无响应),无奈之下只好按电源强制关机了。

第二回合


想起来挂机的时候同时开了两个任务 ( git subtreegit filter-branch ),会不会是这两个任务冲突了?那就一个一个执行吧,重新开始挂机,出门去。

晚上回来之后,电脑"不负所托"又死机了。

第三回合


前两次死机的时候我都不在现场,如果我盯着它,干活应该能认真点?强制关机,再次开启任务,打开任务管理器,我倒要看看是什么原因导致的。

开始之后,cpu开始飙升,查看进程发现竟然不是git而是 电脑管家的实时防护服务,喧宾夺主了吧。想关掉这个服务,试了各种方法关不掉,最后干脆直接卸载。

卸载完电脑管家,重新开始任务。结果cpu还是飙升,这回是win10自带的 Windows Defender, 同理禁用掉。(后来发现,这两个软件应该是对git产生的大量文件进行扫描,虽然会占用一些cpu, 但是并没有太大影响,所以不必禁用)

重新开始,cpu正常了,接下来就是慢慢等待了。半小时,一小时... 一切还算正常,不过内存占用有点上升。按照任务已完成的进度和增长的内存,粗粗算了一下,发现内存根本坚持不到任务结束的那一刻。果然,几个小时之后,内存就满了,磁盘利用率开始飙升,然而任务还有一大半没完成,而且速度越来越慢,不过电脑还能正常使用。继续等待,一个小时后,不出意外,终于死机了。

问题分析


通过上面的试验可以确认,死机的原因是内存泄漏了,但是什么原因导致内存泄漏还无法得知。

下面给出本次迁移使用的机器配置

机器 系统 配置 测试结果
公司的闲置笔记本(A) win10 1703 i5 8G 正常执行迁移任务,不存在内存泄漏
公司的工作笔记本(B) win10 1803 i5 8G 内存泄漏
家里的笔记本(C) win10 1709 i5 8G 内存泄漏

既然有一台电脑是正常的,那就可以排除操作系统的问题了,对比下闲置电脑和我日常使用的电脑有哪些差异 (系统配置,安装的第三方软件等等)。

  1. 首先注意到电脑A的虚拟内存配置和其他两台电脑不太一样,那就调成一样或者关掉虚拟内存试试。结果内存还是会泄漏,不过内存用满了之后任务就因为内存不足自动结束了,也就不会死机了。到这一步可得知死机的原因是 物理内存耗尽后,大量使用磁盘虚拟出来的内存导致的,但是还没从根源上找到内存泄漏的原因。

  2. 对比任务管理器中的运行的服务,一个个关掉后测试,有点费劲费时(这真是个笨方法,后来想到重启进入 安全模式 测一遍就好了)。忽然注意到,前面提到的 电脑管家的实时防护服务Windows Defender 会占用较多的cpu, 那么和它们类似的 扫描类/底层拦截类 的软件也很有嫌疑。这回把目标瞄准 ADSafe 这个广告拦截软件, 禁用服务,再次开启迁移任务。等待了一个小时,内存竟然没有增长,看来真凶就是它了。

问题复现


先上截图,看下开启ADSafe时的资源使用情况

开机后刚开始执行任务 任务运行半小时后

对比前面两张图看下半小时的数据差异:

  1. 资源管理器中 使用中 增长2.1G, 已提交 增长2.9G
  2. 资源监视器中 可用 的内存几乎都转为 正在使用
  3. RAMMap中 进程私有 增长100M, 映射文件 增长1G, 页表 增长1.2G

可以发现进程并没有泄露内存,映射文件 占用的内存不用太在意,唯一异常的地方在于 页表 这一项。

再上一张RAMMap中进程标签页下的截图

RAMMap中进程标签页

可以看到大量的进程, PID 由最初的 1W+ 增长到了 18W+,而且这些进程大部分在任务管理器是不存在的(进程已结束)。粗粗统计了下, 大约有46000个进程( sh.exe/git.exe/cat.exe ), 每个占用28k, 合计大约1.22G, 正好和上面的 页表 增长内存相吻合, 所以应该是这部分内存无法回收利用导致的内存泄漏(这估计是系统的bug, 进程结束应该释放页表占用的内存才对)。类似情况

关掉 ADSafe 后再次试验,sh.exe/git.exe/cat.exe 进程数虽然增加了几十个, 但是和前面的 4W+ 比起来完全不是一个数量级。

结论


通过上面测试,可以定位到内存泄漏的根源: ADSafegit 有所冲突, 导致 git 不断创建新的进程。至于是什么冲突那就无法得知了, 和 ADSafe 说拜拜就好了。

拓展知识


1. 文中用到的内存分析工具: RAMMapVMMapAIDA64 Extreme
2. 关于任务管理器中的内存指标:

使用中: 进程使用的内存大小,内存使用率就是用这个值计算的,实际上这个值并没有太大意义。
已提交(已用): 所有程序真正占用的内存,当这个值接近或者超过物理内存大小的时候,电脑基本已经开始变卡了,因为这时候已经开始使用磁盘所虚拟出来的内存,想想内存和磁盘的读写速度就知道了。
已提交(总): 也就是虚拟内存,等于 物理内存 + 系统盘下pagefile.sys文件的大小

关于 使用中已提交 的区别, 我的理解: 一个进程向操作系统申请了1G的内存,那么这些内存就都归这个进程使用,虽然它现在只使用了200M, 但剩下800M应该为这个进程保留,而不能拿去给别的进程使用,这个例子中 已提交 就是1G, 使用中 是200M,两者之差可以反应出程序的内存利用率。

3. 是否应该禁用"虚拟内存"(pagefile.sys):

个人不建议禁用。比如我平时工作时,开一个idea再把工作项目都启动,基本上8G的内存都用完了,这时如果我再开个chrome就用到了"虚拟内存",内存再挤一点用一点。但是如果我禁用了虚拟内存,就会提示内存不足导致程序崩溃,或者需要关闭使用中的程序释放内存才能打开新的程序。"虚拟内存"的意义在于,物理内存不足的时候使用磁盘来代替内存,虽然会卡一点,但是能满足工作所需(就是要开这么多程序)。同样的,内存不足根本解决办法应该是加内存而不是一味的加大"虚拟内存"。

4. RAMMap中的指标

按照我的经验,剩余可用内存基本上等于 映射文件(备用) + 未使用(归零+可用)。如果开启了Superfetch服务,系统会把一些常用的文件读取到内存(映射文件)中,这样程序中用到这些文件的时候就能更快的读取,这部分内存在内存不足的时候可以拿来给其他进程使用。

5. 关于页表

对于页表我也不了解,页表应该就是一个目录,保存地址映射关系,通过它程序能把逻辑地址转为实际的物理地址。


转载请注明出处:https://www.jianshu.com/p/7510e57aeaff

相关文章

网友评论

    本文标题:记一次win10下的内存泄漏分析

    本文链接:https://www.haomeiwen.com/subject/gbbliftx.html