分析进程中加载​​的本机 DLL 和程序集的内存占用的工具?

Posted

技术标签:

【中文标题】分析进程中加载​​的本机 DLL 和程序集的内存占用的工具?【英文标题】:Tools to analyzing the memory footprint of native DLLs and assemblies loaded in a process? 【发布时间】:2012-04-05 07:25:02 【问题描述】:

根据任务管理器,我有一个拥有 130MB 内存的进程,根据dotTrace,只有 11MB 的实时 .NET 对象,所以我想知道其他 120MB 发生了什么?

我需要一个工具来列出进程中加载​​的程序集和本机 DLL,获取进程中图像的大小,并为每个程序集测量 JITed 方法的内存占用。

来自 SysInternal 的ListDlls 部分完成了这项工作。但它不测量 JITed 代码大小,它只提供原始数据。理想情况下,我想要一个 UI 来分析和总结这些数据。

最近,Visual Studio 团队报告说使用工具PerfView 进行了此类分析。这在博客文章Visual Studio 11 Beta Performance Part #1 中进行了说明,部分:最大的 VM 消费者 - DLL。有人有使用 PerfView 分析原生 Dll 和程序集足迹的经验和反馈吗?

除了ListDllsPerfView,你会推荐其他工具吗?


好的,Simon Mourier 建议的VMMAP 似乎是更适合这项任务的工具。 VMMAP 显示大部分工作集内存进入托管堆栈(下方绿色为 113MB),因此问题更多与 .NET 对象相关,而不是非托管内存。绿色锯齿曲线只是装载/卸载会话的时间线。由于某些原因,我的第一个措施是完全错误的:

dotTrace 告诉我分配了 41MB 的 .NET 对象, WMMAP 显示一个 180MB 的工作集(任务管理器显示类似的数字) WMMAP 显示由 GC 分配的 113MB 托管堆。此托管堆内存中有 90MB 在工作集中:

所以我的计划是:

    确定为什么 GC 为 41MB 的 .NET 对象分配 113MB 的托管堆? (这样的数字正常吗?是高度碎片化的原因吗?) 努力缩小分配的这组 41MB 的 .NET 对象!

【问题讨论】:

【参考方案1】:

既然你提到了 sysinternals 的 ListDlls,还有另一个名为 Process Explorer 的工具包含大量信息,并且比 ListDlls 好得多(你要确保你有最新版本,也有很多 .NET信息,支持64位和32位进程等)。

对于每个进程,您可以同时查看以列或每个进程显示的非托管内存(私有字节等)和托管内存(GC 集合、大型对象堆等)。

sysinternals 的另一个很酷的工具是VMMAP。它是一个进程内存分析实用程序,显示了不同类型的虚拟和物理内存类型的细分。

至于你的 120Mb 问题,你真的想检查所有注入到你的进程中的非托管 DLL,它们不是标准 Windows 安装或标准 DLL 进程集的一部分。对于如此大的分配,我当然会首先跟踪图形组件,因为它们以分配大块内存而闻名(尤其是当您谈到诸如 NDepend 之类的工具时,它 是图形化的)。 Process Explorer 还可以跟踪 GDI 和 USER 对象的数量。

关于 GDI 主题,这里有一个名为 GDIView 的免费工具,它提供了每个进程分配的 GDI 对象的详细信息。

【讨论】:

嗨,我的朋友 Simon,我会尝试 VMMAP,因为他们确实在 VS11 博客文章中提到了它,但他们也提到他们在 VMMAP 之上做了一个工具来利用它的结果。我也会尝试我不知道的 GDIView!谢谢 感谢 Simon,VMMAP 对了解全局有很大帮助。我今天早上的发现似乎主张它更像是一个 GC/托管内存问题,而不是非托管问题。参见上面的精度。知道为什么 GC 为 41MB 的 .NET 对象保留 113MB 的托管内存吗? @PatrickfromNDependteam - 如果它是托管的,那么您应该使用 Windbg 或 Visual Studio (blogs.msdn.com/b/vancem/archive/2006/03/07/545596.aspx) 潜入 SOS (msdn.microsoft.com/en-us/library/bb190764.aspx) 并使用著名的 objsize 命令。它将转储 .NET 对象列表等。 Process Explorer(最新版本)还能够显示 GC 统计信息。您可能还想看看大对象堆,或 LOH (msdn.microsoft.com/en-us/magazine/cc534993.aspx),它是非常特殊的堆(它不能被压缩) 感谢 Simon,我很久以前就尝试过 SOS,本次会议将深入探讨! 您能找出 GC 分配(存储)的内存比所有活动的 .net 对象多的原因吗?【参考方案2】:

我推荐SciTech .NET Memory Profiler。该工具主要用于分析 .NET 内存使用情况,例如查找 .NET 内存泄漏或识别内存压力较大的区域。虽然不是它的主要用途,但它还可以更简单地显示本机内存,包括每个加载库的 JIT 代码大小。我相信您将能够通过此类信息找到这 120 MB 的来源。

【讨论】:

我刚刚试用了 SciTech .NET Memory Profiler 的 v4 版本,但不幸的是,使用此工具后,大部分非托管内存位于:物理内存 > 私有 > 代码 (13.3MB) > (13MB) 和物理内存 > 私有 > 未识别的非托管堆 (130MB) > 数据 (121MB) 顺便说一句,我将分析级别设置为高以获得这些结果,但我猜分析级别与托管对象的相关性比与非托管对象的相关性更高。【参考方案3】:

我使用RedGate ANTS .NET Developer Bundle 处理这些问题。 Memory Profiler 允许识别内存泄漏(如僵尸对象)并制作内存使用情况的快照。然后,您将能够比较两个快照之间的类和实例。 您可以在树中跟踪实例引用并轻松查看维护该引用的***对象。

此外,Performance Profiler 还提供代码分析以识别瓶颈和 CPU 使用率。

多年来,它帮助我们在几分钟内找到应用程序问题。

【讨论】:

我喜欢 RedGate ANTS .NET Memory Profiler,但当前版本没有任何选项来分析我的进程的非托管 120MB。 6.0:red-gate.com/supportcenter/content/ANTS_Memory_Profiler/help/…。 7.0:red-gate.com/supportcenter/…。我这里没有 7.0,但即使我不知道哪些信息可用于非托管内存,也应该有所帮助。 6.0 正确链接:red-gate.com/supportcenter/content/ANTS_Memory_Profiler/help/…。事实上,提供的信息对于 7.0 来说似乎很模糊。

以上是关于分析进程中加载​​的本机 DLL 和程序集的内存占用的工具?的主要内容,如果未能解决你的问题,请参考以下文章

在同一个进程中加载​​同一个 DLL 的 2 个版本

本机库 sqljdbc_auth.dll 已在另一个类加载器中加载

关于JVM案例分析

在 C/C++ (Win64) 中从内存中加载 64 位 DLL

原生 C/C++ 代码的 C++/CLI 包装器,无法在 Unity3D 中加载

避免在 C++/CLI 项目中加载 .Net Dlls?