使用Perfmon.exe调试分析内存不足(OutOfMemory)

32位操做系统的寻址空间是4G,其中有2G被操做系统占用,也就是说留给用户进程的内存只有2G(其中还要扣除程序加载时映像占用的部分空间,通常只有1.6G~1.8G左右可使用)。缓存

若是进程运行中须要申请内存,而操做系统没法为其分配内存空间,则会产生内存不足的异常,在.net中为System.OutOfMemoryException(The exception that is thrown when there is not enough memory tocontinue the execution of a program.)。dom

虽然最终的表现都为OutOfMemoryException,但其产生的缘由多是不同的,动手解决此问题以前须要先对进程当前内存的使用状态进行分析,找出正确的缘由,才能对症下药。下面分享一下调试此类问题的一些心得。性能

1、使用Perfmon.exe测试

1)   命令行输入perfmon.exe。打开“性能”。操作系统

2)   在“性能日志与警报-计数器日志”上右键,选择“新建日志设置”。.net

3)   输入日志名称,如“OOM”。命令行

4)   在“常规-计数器”中删除全部默认的计数器(若是有)。调试

5)   点击“添加计数器”,性能对象选择“.NET CLR Memory”,计数器选择并添加“Bytes in all heaps”、“Large Object Heap Size”。一样“性能对象”选择“Process”,计数器选择并添加“Virtual bytes”、”Private bytes”。注意点击“添加”前须要在“从列表选择范例”选择框选择须要监控的进程。
日志

另外,若是当前系统登录的用例对目标进程没有调试权限,须要在“运行方式”框里填入domain\username,并输入密码。对象

6)   数据采样间隔能够设置小一点,如1秒钟。

7)   点击“肯定“,新的计数器日志就新建成功了。右边的框框中能够看到新的计数器,绿色表示正在运行中。”“日志文件名“列显示了本次监控结果将写入的日志文件名(同一个计数器运行屡次,写入的日志文件名是不一样的)。

8)   让程序与计数器运行一段时间,而后中止计数器(为何要中止计数器?个人机器上测试的时候,须要先中止计数器后,才会把监控的结果写到日志文件中,若是不先中止,在下面的监视器中将看不到计数器运行这段时间的监控结果。)。

9)   点击“系统监视器“。点击”“查看日志数据”(图标为)按钮,在“来源”选项卡里添加日志文件为刚刚咱们新建的计数器产生的日志文件。下方可选择时间范围,这里选所有便可。而后在“数据”选项卡里添加须要查看的计数器(此选择卡还能够定义不一样的计数器显示的样式及显示比例)。

10) 从图上能够看到在计数器运行的时间段中,被监控进程的内存使用状况。在添加计数器的窗口中有对相应计数器的简单说明,下面是几个经常使用的计数器:

·           Bytes in all Heaps:.net托管堆(GC)使用的总内存。包括0代、1代、2代及大对象堆。

·           Large Object Heap size:大对象堆使用的内存。.net在分配内存时大于85K的对象会被放到这个堆中,不一样于0、一、2代,大对象堆中的内存不是连续的,在垃圾回收时也不会移动大对象的地址(我系统显示为大于20K对象为大对象,实际上2.0应该为大于85K)。

·           Private bytes:该计数器记录了当前经过VirtualAlloc API Commit的Memory数量。不管是直接调用API申请的内存,被Heap Manager申请的内存,或者是CLR 的managed heap,都算在里面。跟Handle Count同样,若是在整个程序周期内整体趋势是连续向上,说明有MemoryLeak(摘自百度)。

·           Virtual bytes:该计数器记录了当前进程申请成功的用户态总内存地址,包括DLL/EXE占用的地址和经过VirtualAlloc API Reserve的Memory Space数量,因此该计数器应该总大于Private Bytes。通常来讲,Virtual Bytes跟Private Bytes的变化大体一致。因为内存分片的存在, Virtual Bytes跟Private Byes通常保持一个相对稳定的比例关系。当Virtual Bytes跟Private Bytes的比例关系大于2的时候,程序每每有比较严重的内存地址分片(摘自百度,但对.net程序来讲通常差异在200M如下还算是正常的)。

11) 有了上面几个计数器的结果以后,通常能够经过如下规则大体定位问题的所在:

·           Virtual bytes增加但Private bytes没有显著增加。为Virtual bytes泄露。

·           Private bytes增加但bytes in all heaps没有显著增加。为非托管资源泄露,检查有没有COM组件或其它非托管调用没有正确释放内存。

·           Bytes in all heaps显著增加。为.net托管内存泄露。因为.net内存是GC管理的,自动回收,这里有多是缓存了过多的数据,或程序中引用混乱致使原本须要被回收的数据还被其它对象所引用从而GC无法回收这部分数据。

·           Bytes in all heaps有增加但使用很少,系统剩余可用内存也比较多(须要再添加相应的计数器)。这种状况比较少见,但我遇到过一次是因为非托管在存在大量碎片,致使.net在申请大对象时失败。原文:https://blog.csdn.net/lazyleland/article/details/6704661

相关文章
相关标签/搜索