什么是专用字节,虚拟字节,工作集?


490

我正在尝试使用perfmon Windows实用程序来调试进程中的内存泄漏。

这是perfmon解释这些术语的方式:

工作集是此进程工作集的当前大小(以字节为单位)。工作集是进程中的线程最近接触的一组内存页面。如果计算机中的可用内存超过阈值,则即使不使用这些页面,它们也将保留在进程的工作集中。当可用内存低于阈值时,将从“工作集”中修剪页面。如果需要它们,将在离开主存储器之前将它们软故障恢复到工作集中。

虚拟字节是进程正在使用的虚拟地址空间的当前大小(以字节为单位)。使用虚拟地址空间并不一定意味着相应使用磁盘或主内存页面。虚拟空间是有限的,该过程可能会限制其加载库的能力。

专用字节数是该进程已分配的当前无法与其他进程共享的内存大小(以字节为单位)。

这些是我的问题:

我是否应该测量私有字节,以确保该进程是否有泄漏,因为它不涉及任何共享库,并且如果发生泄漏,将来自该进程本身?

进程消耗的总内存是多少?是虚拟字节还是虚拟字节与工作集的总和?

专用字节,工作集和虚拟字节之间是否有任何关系?

是否有其他工具可以更好地了解内存使用情况?


3
更好的工具应该是valgrind / helgrind,但是不幸的是,不是在Windows下:(
Kornel Kisielewicz 2009年

我是否应该测量专用字节以确保进程是否有泄漏 如果进程的专用字节没有增长,那么就没有内存泄漏。如果它们增长,可能是由于内存泄漏,也可能是由于内存碎片。我认为很难说出专用字节的增长是什么意思。

@SergeiKurenkov我们可以说的一件事是,它永远不会归因于“内存碎片”。
Jamie Hanrahan

Answers:


517

这个问题的简短答案是,这些值均不能可靠地指示可执行文件实际使用了多少内存,并且它们都不适合调试内存泄漏。

专用字节是指进程可执行文件要求的内存量,不一定是实际使用的内存量。它们是“私有的”,因为它们(通常)不包括内存映射文件(即共享的DLL)。但是-这很重要-它们不一定排除那些文件分配的内存。无法判断私有字节的更改是由于可执行文件本身还是由于链接库引起的。专用字节也不是唯一的物理内存。它们可以分页到磁盘或备用页列表中(即不再使用,但也没有分页)。

工作集是指该进程使用的总物理内存(RAM)。但是,与专用字节不同,它还包括内存映射文件和各种其他资源,因此它的度量甚至比专用字节低。这与任务管理器的“内存使用情况”中报告的值相同,并且近年来一直是无休止的混乱之源。从某种意义上讲,可以解决工作集中的内存而无页面错误;然而,在待机页面名单仍然物理内存中但没有报告的工作组,这就是为什么你会看到“内存使用”当最小化的应用程序突然下降。

虚拟字节是整个过程占用的虚拟地址空间。从某种意义上说,这就像工作集,因为它包括内存映射文件(共享的DLL),但是它还包括备用列表中的数据以及已经被调出并位于磁盘上某个页面文件中的数据。系统在高负载下由每个进程使用的虚拟字节总数将比计算机实际拥有的内存多得多。

因此,关系为:

  • 专用字节是您的应用程序实际分配的,但包括页面文件的使用情况;
  • 工作集是非分页的专用字节加上内存映射的文件;
  • 虚拟字节是工作集以及分页的专用字节和备用列表。

这里还有另一个问题。就像共享库可分配内存,应用程序模块内部,导致潜在的误判在应用程序的专用字节报道,您的应用程序也可能最终会内部分配的内存共享模块,导致假阴性。这意味着您的应用程序实际上有可能发生内存泄漏,而该泄漏根本不会出现在“专用字节”中。不太可能,但可能。

专用字节是可执行文件正在使用的内存量的合理近似值,可用于帮助缩小潜在的内存泄漏候选对象的范围。如果您看到数量不断增加并且不断增长,则需要检查该过程是否泄漏。但是,这不能证明存在或不存在泄漏。

实际上,Visual Studio是检测/纠正Windows中内存泄漏最有效的工具之一(链接转到使用VS进行内存泄漏的页面,而不是产品页面)。 Rational Purify是另一种可能性。Microsoft 在此主题上也有一个更通用的最佳实践文档。在上一个问题中列出了更多工具。

我希望这可以清除一些问题!跟踪内存泄漏是调试中最困难的事情之一。祝好运。


26
恐怕您的回答不太正确。专用字节指的是进程可执行文件要求的内存(RAM)数量-不仅是物理内存。因此,您可以通过监视专用字节来确保检查大多数内存泄漏情况。尝试:: VisualAlloc提交大量内存(例如1.5G)。您应该能够看到您的私有字节远大于工作集。证明您的“工作集是专用字节加内存映射文件”是不正确的。
周杰伦

4
实际上,我相信写的理解是“工作集是内存中的专用字节加内存映射的文件”。并且可以交换专用字节-您可以看到专用字节大于计算机中的物理内存。
周杰伦

2
@Aaronaught:关于可靠指示器以及适合调试的第一个陈述令人困惑。专用字节是应用程序内存空间泄漏的可靠指示。它可能是一个依赖的DLL,可能是间接的,但它是应用程序内存空间中的泄漏。您能解释为什么它不能用于调试吗?应用程序进程的完整内存转储应告诉我们正在消耗此内存的内容。我不确定我为什么不能将其用于调试。你能阐明一点吗?
G33kKahuna 2012年

@ G33kKahuna:我不清楚内存转储如何以任何有意义的方式告诉您正在消耗内存的内容-除非用“什么”来表示“什么模块”,但是您所拥有的只是一个快照,您仍然看不到除非您在一段时间内并在严格控制的条件下进行了几次转储,否则哪个模块实际上会随着时间泄漏内存。很难想到一种效率更低,不可靠的调试策略。这些天探查器无处不在。用一个。
亚伦诺特,2012年

1
运行完整的!objsize,这应该显示立即堆中的所有固定对象。您可以通过检查eeheap -gc进行确认。这应该向您显示卷卡住的位置。通常,如果上述所有命令均未提供任何提示,则私有字节将由GC中未收集的对象占用。现在,继续前进到gchandles或gcleaks。这些命令应该告诉您不能映射哪些类型/对象地址。指针仍然在那里,但是对象不见了。对于未发布的事件处理程序,这是一个绝对的问题。
G33kKahuna 2012年

10

您不应尝试使用perfmon,任务管理器或类似工具来确定内存泄漏。它们对于识别趋势很有用,但对其他方面没有什么帮助。他们绝对报告的数字过于模糊和汇总,无法用于特定任务,例如内存泄漏检测。

先前对该问题的答复已很好地解释了各种类型。

您询问有关工具的建议:我建议使用Memory Validator。能够监视进行数十亿内存分配的应用程序。

http://www.softwareverify.com/cpp/memory/index.html

免责声明:我设计了内存验证器。


1
我什至不能运行一个简单的类文件(在Java中)?是什么赋予了?
jn1kk 2012年

我怀疑斯蒂芬和魔鬼有某种联系,甚至被克隆 ...:D;)
罗伯特·科里特尼克

@StephenKellett,有试用版吗?
Pacerier,2015年

@Pacerier(如果您单击链接)在页面左侧的购买选项上方有x86和x64版本的试用版。
Bradley A. Tetreault 2015年

10

自开始以来,perfmon计数器的定义就被破坏了,由于某种原因,似乎很难纠正。

在MSDN上的视频“ 揭示了内存管理的奥秘”中,可以很好地概述Windows内存管理:它涵盖的主题比跟踪内存泄漏(例如工作集管理)所需的主题更多,但在相关主题中提供了足够的详细信息。


为了给您有关perfmon计数器描述的问题的提示,这是MSDN上“ Private Bytes Performance Counter-Beware! ”中有关私有字节的内部故事:

问:什么时候专用字节不是专用字节?

答:不在时。

专用字节计数器报告该过程的提交费用。也就是说,交换文件中已分配的空间量,用于在交换出专用内存时保留私有内存的内容。注意:我避免使用“ reserved”一词,因为它可能与未提交的保留状态下的虚拟内存产生混淆。


从MSDN上的“ 性能计划 ”中:

3.3专用字节

3.3.1说明

专用内存定义为分配给某个进程的内存,其他进程无法共享。当在计算机上执行多个此类进程时,此内存比共享内存更昂贵。(传统)非托管dll中的专用内存通常由C ++静态变量组成,并且约为dll总工作集的5%。


1
之所以投票,是因为有很多关于如何破解的好例子!
布鲁诺·布兰特

第一个引号是错误的。分配“专用字节”不需要“分配在交换文件”(实际上称为页面文件)中的任何内容。您甚至不必具有分配“专用字节”的页面文件。实际上,分配专用字节不会立即在任何地方使用任何空间,并且可能永远不会使用分配的空间。
杰米·汉拉汉

第二个引用不是更好。DLL代码中使用的专用字节不一定在DLL中大部分静态分配。DLL代码完全可以自由调用VirtualAlloc,HeapAlloc(CRTL中的malloc和new)等。它还尝试将私有内存大小描述为工作集大小的百分比,这是荒谬的。前者是虚拟大小(对于具有相同输入的代码的每次使用,大小都是相同的),而后者是物理大小(根据每次运行的内存量多少,它可能与一次运行完全不同)-机器饿了)。
Jamie Hanrahan

5

这里有一个有趣的讨论:http : //social.msdn.microsoft.com/Forums/en-US/vcgeneral/thread/307d658a-f677-40f2-bdef-e6352b0bfe9e/ 我对这个线程的理解是释放小分配是没有反映在专用字节或工作集中。

长话短说:

如果我打电话

p=malloc(1000);
free(p);

那么专用字节仅反映分配,而不反映释放。

如果我打电话

p=malloc(>512k);
free(p);

那么专用字节正确反映了分配和释放。


7
C标准库内存函数使用自定义或Win32堆的事实解释了这一点,这是低级进程级内存管理之上的内存管理机制。
Kyberias

@Kyberias,那么,我们如何得到下面呢?
Pacerier,2015年

while(1)免费(malloc(1000)); //这是否会导致Private Bytes永远增加?
franckspike 2015年

2
@franckspike:不,它将增加到某个点(通常约为4 kB,但这可能会有所不同),然后停止,因为CRT将重新使用以前释放的内存,而不是从OS请求新页面。
Miral

@Pacerier:您可以调用VirtualAlloc和VirtualFree。
杰米·汉拉汉
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.