你的记忆被释放,但它并不那么容易看到。缺少一些工具(除了带有SOS的Windbg)以显示当前分配的内存减去死对象。 Windbg为此提供了!DumpHeap -live选项,仅显示活动对象。
我试图从AndyJ https://dotnetfiddle.net/wOtjw1
首先,我需要创建具有DataTable的内存转储有一个稳定的基线小提琴。 MemAnalyzer https://github.com/Alois-xx/MemAnalyzer是正确的工具。
MemAnalyzer.exe -procdump -ma DataTableMemoryLeak.exe DataTable.dmp
这需要SysInternals的procdump在您的路径中。
现在你可以运行队列执行方案和托管堆上比较分配指标:
C>MemAnalyzer.exe -f DataTable.dmp -pid2 20792 -dtn 3
Delta(Bytes) Delta(Instances) Instances Instances2 Allocated(Bytes) Allocated2(Bytes) AvgSize(Bytes) AvgSize2(Bytes) Type
-176,624 -10,008 10,014 6 194,232 17,608 19 2934 System.Object[]
-680,000 -10,000 10,000 0 680,000 0 68 System.Data.DataRow
-7,514 -88 20,273 20,185 749,040 741,526 36 36 System.String
-918,294 -20,392 60,734 40,342 1,932,650 1,014,356 Managed Heap(Allocated)!
-917,472 0 0 0 1,954,980 1,037,508 Managed Heap(TotalSize)
这说明我们有917KB的内存与数据表的方式分配和10K DataRow的实例是仍然在托管堆上游荡。但这些数字是否正确?
号
因为大多数的对象是已经死了,但没有完整的GC没有发生之前,我们确实需要一个内存转储这些对象仍然报告为活着。解决方法是告诉MemAnalyzer考虑只有扎根(活)对象,如WinDBG的做它用-live选项:
C>MemAnalyzer.exe -f DataTable.dmp -pid2 20792 -dts 5 -live
Delta(Bytes) Delta(Instances) Instances Instances2 Allocated(Bytes) Allocated2(Bytes) AvgSize(Bytes) AvgSize2(Bytes) Type
-68,000 -1,000 1,000 0 68,000 0 68 System.Data.DataRow
-36,960 -8 8 0 36,960 0 4620 System.Data.RBTree+Node<System.Data.DataRow>[]
-16,564 -5 10 5 34,140 17,576 3414 3515 System.Object[]
-4,120 -2 2 0 4,120 0 2060 System.Data.DataRow[]
-4,104 -1 19 18 4,716 612 248 34 System.String[]
-141,056 -1,285 1,576 291 169,898 28,842 Managed Heap(Allocated)!
-917,472 0 0 0 1,954,980 1,037,508 Managed Heap(TotalSize)
的DataTable的方法仍然需要,因为额外的DataRow 141056个字节的内存,对象[]和System.Data.RBTree + Node []实例。仅测量工作集是不够的,因为托管堆已被取消分配。如果GC认为下一个内存峰值不远,GC可以保留大量内存。因此,测量提交的内存几乎是毫无意义的度量标准,除非您的(非常低的)目标是仅修复GB内存泄漏。
来衡量事物的正确方法是测量
- 非托管的总和堆
- 分配托管堆
- 内存映射文件
- 页面文件出炉的内存映射文件(可共享内存)
- Private Bytes
这实际上正是MemAnalyzer用-vmmap开关所做的,它在Sysinternals的路径中对vmmap进行了预期。
MemAnalyzer -pid ddd -vmmap
这样,您还可以跟踪非托管内存泄漏或文件映射泄漏。 MemAnalyzer的返回值是以KB为单位的总分配内存。
- 如果使用-vmmap,它将报告上述点的总和。
- 如果vmmap不存在,它将只报告分配的托管堆。
- 如果添加了-live,则仅报告有根管理的对象。
我的确编写了这个工具,因为我的知识中没有任何工具可以让我们以整体的方式查看内存泄漏。我总是想知道是否泄漏内存,无论它是否管理,非托管或其他。
通过写diff输出的一个CSV文件,您可以轻松地创建透视差异图表类似上面。
MemAnalyzer.exe -f DataTable.dmp -pid2 20792 -live -o ExcelDiff.csv
这应该给你一些想法,如何以更准确的方式跟踪分配指标。
在垃圾收集器不能与您的代码同步的托管环境中,测量已用内存非常棘手。 – Steve
听起来你想要一个队列? https://msdn.microsoft.com/en-us/library/7977ey2c(v=vs.110).aspx –
AndyJ
你需要一个反向计数器来正确处理这个问题..看看这个简单的例子在这里https:/ /stackoverflow.com/questions/5648339/deleting-specific-rows-from-datatable – MethodMan