先上vmmap工具下载链接:
链接:https://pan.baidu.com/s/1EqdKrVR-BXdGAmIOmYcWYw
提取码:2af3
一、什么是内存泄漏?
内存泄漏是指程序分配内存,然后在不再需要时不将其归还。泄漏的内存被浪费了,因为程序本身不再使用它,但在程序退出之前没有其他东西可以使用它。
高内存使用率并不总是意味着存在内存泄漏。如果您正在做的事情本身就需要大量内存,并且在操作完成后该内存被返还,那么这不是内存泄漏。
内存泄漏通常是无界。如果你继续做一些触发泄漏的事情,那么内存使用通常会不断增加。(如果内存使用量只在你第一次做某事时增加,而且增加不是很大,那么它可能只是一个分配缓存的组件,它将重新使用它以加快未来的操作。这样的缓存通常在一个几分钟不活动,尽管这取决于组件。)
二、使用 VMMap 查找内存泄漏
如果您使用任务管理器查看,它可能会说 explorer.exe 或 dopus.exe 正在使用大量内存,但它不会告诉您在哪里责怪谎言。程序本身可能存在错误,但它几乎总是第三方组件。这是找出哪一个的方法。
下载免费的 VMMap 工具从 Microsoft/SysInternals 中提取其 zip 文件。VMMap 是一个低级调试工具,但别担心,我们要用它做的事情很简单。
1. 双击 VMMap.exe,它应该会打开一个包含正在运行的进程列表的窗口。
在该窗口的顶部,单击Launch and trace a new process选项卡,然后输入 dopus.exe 的路径,如下所示。
不要单击“确定”。
2. 在点击确定之前,您需要退出 Directory Opus (dopus.exe),以便 VMMap 重新启动它。(这将允许 VMMap 记录新 dopus.exe 所做的内存分配。) 默认情况下,
简单地关闭所有 Opus 窗口不会退出它。使用 Opus 托盘图标菜单上的退出选项。(另请参阅:如何退出 Directory Opus。)
3. 现在在 VMMap 中点击 OK;它应该重新启动 Opus。
VMMap 还会显示一个彩色数字列表,但不要担心理解它们。:)
保持 VMMap 和 Opus 运行;从现在开始不要关闭它们中的任何一个。
4. 以触发内存泄漏的方式使用 Directory Opus。
理想情况下,多次触发泄漏,使其大而容易找到。(如果可以的话,让它至少泄漏 10MB,或者更多,这样它就可以从其他内存分配中脱颖而出。)
使用标准的任务管理器来关注 dopus.exe 的内存使用情况,这样你就可以知道何时触发了泄漏.
5. 返回 VMMap 并按F5(或单击View -> Refresh)使其刷新。
6. 单击VMMap 窗口底部的Trace...:
7. 在出现的跟踪窗口中,按字节列排序并滚动到列表顶部。
它应该看起来像这样,其中第一项的 Bytes 值比其他项大得多: 如果第一项没有相对较大的 Bytes 值,那么您可能需要多次触发泄漏(保持 VMMap 运行并记住每次回到它时都要刷新它),否则您可能根本不正确地认为存在泄漏。否则,继续...
8. 选择第一项,然后单击Trace 窗口底部的Stack...。
9. 您现在将看到分配内存时涉及的 DLL(和 dopus.exe)列表,如下所示: 导致内存泄漏的组件通常是列表中的第一个非 Windows DLL。您通常可以忽略路径以C:\Windows开头的那些(例如 ntdll.dll 和 user32.dll)。 在上面的例子中,内存泄漏是由 LeakyShellExtension.dll 引起的,你可以猜到,这是我为本指南编写的一个 shell 扩展,它故意泄漏内存。我写它是为了每次右键单击一个文件时泄漏大约 10MB,然后右键单击文件几次,使其总共泄漏大约 70MB。
10.一旦你有一个可疑的DLL,名称和路径通常足以识别它属于什么。如果没有,请在磁盘上找到 DLL,右键单击它,选择“属性”,然后转到“详细信息”选项卡。这通常包含有关谁制作它以及它是什么的信息。
有时也值得查看列表中的其他一些 DLL。
一旦您知道 DLL 属于什么,您可以尝试卸载(或更新)它以查看泄漏是否消失。
如果泄漏消失,那么您就知道向谁报告错误。
如果泄漏仍然存在,请重复该过程并查看指示了哪些 DLL。如果它又是同一个 DLL,那么您就知道您没有成功卸载它。如果它是另一个 DLL,也许第一个是无辜的,可以重新安装。
三、vmmap内存指标详解
任务管理器中关于内存的两个重要概念:private和working set。但是内存远不止那么简单,下面我根据VMMap来详细介绍一下内存的分类。
内存是一个很复杂的系统,其中的paging file,sharable memory,reserve和commit等概念使得要算清楚一个进程到底使用了多少内存几乎成了不可能的事情了。
还好我们有VMMap这个工具,它用两个纬度将内存进行了详细的划分。
一个是纵向的纬度,也就是内存是从哪里来的。分为
1、Image(可执行文件),
2、Mapped file(由CreateFileMapping以文件作为back up)。
3、Sharable(由CreateFileMapping以内存作为 back up)
4、Private Data(由Virtual Alloc分配)
5、Heap(由new,GlobalAlloc和HeapAlloc等分配)
6、Stack(栈占用的控件)
7、Page table(内核里面维护当前虚拟地址控件所需要的内存)
8、Managed Heap(由.NET garbage collector分配和管理)
还有一个横向的维护,分别被称为:
Size: 总体大小,包括了commit和没有reservce的内存。如果这项和Committed不 一致,那么就是说有reserve的内存。
Committed: committed的大小,包括Private内存和可共享的内存。
Private:属于当前进程的虚拟内存,指的是当你修改他时仅仅当前进程会受到影响。(copy-on-wirte属性的页面还没被修改时也属于此类)
以上实际上是虚拟内存(virtual memory)的概念,其中的内容可能被物理内存(physical memory)back up,也可能被Paging file back up。
而以下的几个指标指的是物理内存:
Total WS: 所有的working set,包括private working set和sharable working set。
Private WS: private working set。仅属于当前进程的working set。
Sharable WS。可共享的working set。
Shared WS。已经共享的working set,这个值应该是sharable working set的一部分或者全部。
四、vmmap实践验证总结
实际运行应用程序各个内存区域的使用情况如下图(F5刷新):