资源泄漏相关笔记
计数器
.Net Memory
- # Bytes in all Heaps
1、2代与LOH的总和,不包括0代
托管堆的大小应该是64M(若为工作站则为16M)-1代大小+此数值
计算总内存大小还得包括.net栈、模块本身的大小、非托管资源(线程等)大小
- Allocated Bytes/sec
分配速率
分配速度高会引发垃圾收集频繁(#Time in GC)
- #GC Handles
垃圾回收要处理的句柄(非托管资源)数目
- #Induced GC
手动触发GC的次数
- #Time in GC
上次GC结束到当前这次GC结束,当前GC所消耗的时间的百分比
正常为10%以下
- #Total Committed Bytes
GC上提交的虚拟内存大小
虚拟内存>=物理内存
虚拟内存中有一部分对应物理内存,而不仅只是物理内存的扩展
“commit memory”为虚拟内存文件中已被占据使用的空间
“reserved momory”为应用程序申请的虚拟内存空间,但并未占据使用虚拟内存文件或主物理内存
Promoted Finalization-Memory from Gen 0
只因等待被终结而被从0代堆提升至1代堆的对象的大小
可以说明较新创建的有析构方法(即使用了非托管资源)的对象数量
- #of Pinned Objects
内存中无法移动的对象的数目
一般是由于非托管代码造成
可能造成内存碎片,最终引发OOM(Out Of Memory)异常
- Gen 0 heap size
0代中的可分配空间的大小
与Gen 1/2 heap size不同的是它不用于衡量第0代堆的大小,而仅表示其中的空间预算
- Gen 1 heap size
1代堆的大小
完全被分配,无空闲空间
1代堆中的资源全是0代堆移过来的
- Large Object Heap size
大对象堆的大小
包含空闲空间
资源泄露情况分类
非托管资源泄露
- private bytes会特别大
此时可以通过“!gchandles”命令查看所有句柄对象
- 句柄对象的数目即非托管资源的数目
- 通过“!FinalizeQueue”命令查看终结队列
- 托管对象使用了非托管资源,并通过析构方法对其进行释放,而实现了析构方法的对象都会出现在终结队列中
- 观察队列中各托管对象的数目,以确定造成非托管资源泄露的托管对象
参考
用Windbg调试.NET程序的资源泄漏
.NET内存管理、垃圾回收
Memory Performance Counters
内存性能计数器
Garbage Collection: Automatic Memory Management in the Microsoft .NET Framework
分析性能瓶颈 — 调试OutOfMemoryException
《你不常用的c#之五》:Thread与ThreadPool的内存之战