【问题标题】:What is the ClrMD equivalent to !DumpHeap -live?与 !DumpHeap -live 等效的 ClrMD 是什么?
【发布时间】:2016-05-18 01:25:52
【问题描述】:

ClrMD 是检查实时可执行文件或内存转储的绝佳工具。要将所有托管堆对象转储为摘要,您可以使用

https://blogs.msdn.microsoft.com/dotnet/2013/05/01/net-crash-dump-and-live-process-inspection/

var stats = from o in heap.EnumerateObjects()
            let t = heap.GetObjectType(o)
            group o by t into g
            let size = g.Sum(o => (uint)g.Key.GetSize(o))
            orderby size
            select new
            {
                Name = g.Key.Name,
                Size = size,
                Count = g.Count()
            };

foreach (var item in stats)
    Console.WriteLine("{0,12:n0} {1,12:n0} {2}", item.Size, item.Count, item.Name);

效果很好,相当于 Windbg 中带有 SOS 扩展的 !DumpHeap -stat。对于回归测试,通常希望在测试后检查对象是否泄漏。这看起来非常适合上面的代码,但不幸的是它会产生误报,因为可能有些对象不再是 root,但它们仍会在摘要中报告。尽管没有泄漏,但这可能会导致报告的泄漏。

SOS 已通过添加 !DumpHeap -live 开关来缓解此问题。什么是等效的 ClrMD 代码来仅获取活动对象,因此回归测试仅因真实原因而失败?

我想我需要使用 ClrType.EnumerateRefsOfObjectCarefully 递归地遍历堆栈,直到找到一个根对象 (ClrHeap.EnumerateRoots),但这种方法需要许多临时 Hashset跟踪递归对象图。这是唯一的方法,还是在 MS 内部某个地方已经有一个正确且性能良好的可用示例(PerfView 来源?)。

【问题讨论】:

    标签: .net clr clrmd


    【解决方案1】:

    我在https://harshaprojects.wordpress.com/2015/12/29/clr-md-analyzing-live-process/#comment-32 找到了一些不错的博客,其中包含我所追求的内容。为了完整起见,我在这里发布代码。

    ObjectSet 类是一个内存效率更高的 HashSet,因为 HashSet 会导致作者机器上的 OOM。我使用 EnumerateRefsOfObjectCarefully 是因为这与 PerfView 使用的方法相同(我猜是出于某种原因)。

    现在这也是我的开源 WMemoryProfiler v.2.2 的一部分

    https://wmemoryprofiler.codeplex.com/releases/view/619764

    让您可以选择带有 SOS 或 ClrMD 的 Windbg 来自动分析流程。

        private static ObjectSet GetLiveObjects(ClrHeap heap)
            {
                ObjectSet considered = new ObjectSet(heap);
                Stack<ulong> eval = new Stack<ulong>();
    
                foreach (var root in heap.EnumerateRoots())
                    eval.Push(root.Object);
    
                while (eval.Count > 0)
                {
                    ulong obj = eval.Pop();
                    if (considered.Contains(obj))
                        continue;
    
                    considered.Add(obj);
    
                    var type = heap.GetObjectType(obj);
                    if (type == null)  // Only if heap corruption
                        continue;
    
    
                foreach (var child in heap.GetObject(obj).EnumerateReferences(carefully:true,considerDependantHandles:true))
                {
                    if (!considered.Contains(child.Address))
                        eval.Push(child.Address);
                }
                
    
                return considered;
            }
    

    【讨论】:

      猜你喜欢
      • 2011-07-02
      • 1970-01-01
      • 2019-06-26
      • 2011-03-11
      • 2010-11-27
      • 1970-01-01
      • 1970-01-01
      • 2018-01-16
      • 2017-05-26
      相关资源
      最近更新 更多