ClrMD相当于什么!转储堆 - 活



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);

这很好用,相当于 !DumpHeap -stat in Windbg with the SOS Extension.对于回归测试,通常需要在测试后检查对象是否泄漏。这看起来非常适合上面的代码,但不幸的是它会产生误报,因为可能有些对象不再植根,但它们仍然在摘要中报告。这可能会导致报告的泄漏,尽管没有泄漏。

SOS 已通过将 !转储堆-live 开关。等效的 ClrMD 代码是什么,只能获取活动对象,以便回归测试仅因真正原因而失败?

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

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

类是内存效率更高的哈希集,因为 HashSet 会在作者计算机上导致 OOM。我使用EnumerateRefsOfObjectCare,因为这是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;
        }

最新更新