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

pan*_*ajt 463 debugging operating-system memory-leaks memory-management

我试图使用perfmon Windows实用程序来调试进程中的内存泄漏.

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

Working Set是此过程的工作集的当前大小(以字节为单位).工作集是过程中线程最近触及的一组内存页面.如果计算机中的可用内存超过阈值,则即使不使用页面,页面也会保留在进程的工作集中.当可用内存低于阈值时,将从工作集中剪裁页面.如果需要它们,它们将在离开主存储器之前被软故障返回工作集.

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

Private Bytes是此进程分配的内存的当前大小(以字节为单位),无法与其他进程共享.

这些是我的问题:

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

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

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

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

Aar*_*ght 487

对这个问题的简短回答是,这些值都不是可执行程序实际使用的内存量的可靠指标,并且它们都不适合调试内存泄漏.

Private Bytes指的是进程可执行文件要求的内存量- 不一定是它实际使用的量.它们是"私有的",因为它们(通常)排除了内存映射文件(即共享DLL).但是 - 这是捕获 - 它们不一定排除那些文件分配的内存.没有办法判断私有字节的更改是由于可执行文件本身还是由于链接库.专用字节也不仅仅是物理内存; 它们可以被分页到磁盘或备用页面列表(即不再使用,但也没有被分页).

工作集是指进程使用的总物理内存(RAM).但是,与专用字节不同,这还包括内存映射文件和各种其他资源,因此它比专用字节的测量精度更低.这与在任务管理器的"内存使用"中报告的值相同,并且近年来一直是无穷无尽的混淆源.工作集中的内存是"物理的",因为它可以在没有页面错误的情况下进行处理; 然而,在待机页面名单仍然物理内存中但没有报告的工作组,这就是为什么你会看到当最小化应用程序中的"内存使用"突然下降.

虚拟字节是整个进程占用的总虚拟地址空间.这就像工作集一样,它包含内存映射文件(共享DLL),但它还包括备用列表中的数据和已经被分页的数据,并且位于磁盘上的页面文件中.在高负载下系统上的每个进程使用的总虚拟字节将比机器实际拥有的内存大得多.

所以关系是:

  • Private Bytes是您的应用实际分配的内容,但包含页面文件使用情况;
  • Working Set是非分页私有字节加内存映射文件;
  • 虚拟字节是工作集加分页的专用字节和备用列表.

这里还有另一个问题; 就像共享库可以在应用程序模块内部分配内存,导致你的应用程序的专用字节报告的潜在误报,您的应用程序也可能最终会内部分配的内存共享模块,导致假阴性.这意味着您的应用程序实际上可能存在内存泄漏,而这种内存泄漏根本不会出现在Private Bytes中.不太可能,但可能.

Private Bytes是您的可执行文件使用的内存量的合理近似值,可用于帮助缩小内存泄漏的潜在候选列表; 如果你看到这个数字不断增长并且不断增长,你会想要检查这个过程是否有泄漏.但是,这不能证明存在或没有泄漏.

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

我希望这清除了一些事情!追踪内存泄漏是调试中最困难的事情之一.祝好运.

  • 我担心你回答的不太正确.Private Bytes指的是进程可执行文件要求的内存量(RAM) - 不仅仅是物理内存.因此,您可以通过监视专用字节来检查大多数内存泄漏情况.尝试:: VisualAlloc提交大量内存(比如说1.5G).您应该能够看到您的私有字节比工作集大.这证明您的"工作集是私有字节加内存映射文件"是不正确的. (26认同)
  • 实际上,我相信写作理解是"工作集是内存中的私有字节加内存映射文件".并且可以交换专用字节 - 您可以看到专用字节大于机器中的物理内存. (4认同)
  • @Aaronaught:关于可靠指标和适合调试的第一个声明令人困惑.专用字节是泄漏应用程序内存空间的可靠指示器.它可能是一个依赖的DLL和间接但它是应用程序内存空间的泄漏.你能解释为什么它不能用于调试吗?应用程序进程的完整内存转储应告诉我们消耗此内存的内容.我不确定我理解为什么它不能用于调试.你能解开一些光吗? (2认同)
  • 运行一个完整的 !objsize,这应该显示直接堆中的任何固定对象。您可以通过检查 eeheap -gc 来确认。这应该会向您显示音量卡住的位置。通常,如果上述所有命令都没有可用提示,则您的私有字节将被 GC 中未收集的对象消耗。现在转到 gchandles 或 gcleaks。这些命令应该告诉你哪些类型/对象地址不能被映射。指针还在,但对象不见了。对于未发布的事件处理程序来说,这是一个非常明显的问题。 (2认同)

Ste*_*ett 10

您不应该尝试使用perfmon,任务管理器或任何类似的工具来确定内存泄漏.它们有助于识别趋势,但不是很多.他们以绝对术语报告的数字过于模糊和聚合,无法用于特定任务,如内存泄漏检测.

之前对这个问题的回答很好地解释了各种类型的内容.

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

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

免责声明:我设计了Memory Validator.


小智 9

perfmon计数器的定义从一开始就被打破了,由于某种原因似乎太难以纠正.

MSDN上的视频" 内存管理之谜 "中提供了对Windows内存管理的一个很好的概述:它涵盖了跟踪内存泄漏所需的更多主题(例如工作集管理),但在相关主题中提供了足够的细节.


为了给你一个关于perfmon计数器描述的问题的提示,这里是关于MSDN上" Private Bytes Performance Counter - Beware! "的私有字节的内幕故事:

问:私有字节何时不是私有字节?

答:当它不是居民时.

Private Bytes计数器报告进程的提交费用.也就是说,交换文件中分配的空间量,用于在交换出来时保存私有内存的内容.注意:我避免使用"保留"一词,因为可能会混淆未提交的保留状态中的虚拟内存.


来自MSDN上的" 性能规划 ":

3.3私人字节

3.3.1描述

专用内存定义为为进程分配的内存,不能被其他进程共享.当多台此类进程在计算机上执行时,此内存比共享内存更昂贵.(传统)非托管dll中的私有内存通常由C++静态构成,并且大约是dll总工作集的5%.

  • “揭示内存管理之谜”会导致 404。链接一个好的网站是一件好事,但至少引用结论通常是更好的主意。因为“互联网永远不会忘记”是不正确的 (2认同)

mca*_*nti 5

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

长话短说:

如果我打电话

p=malloc(1000);
free(p);
Run Code Online (Sandbox Code Playgroud)

那么私有字节只反映分配,而不是反释.

如果我打电话

p=malloc(>512k);
free(p);
Run Code Online (Sandbox Code Playgroud)

那么私有字节正确地反映了分配和释放.

  • 这可以通过以下事实来解释:C标准库存储器函数使用自定义或Win32堆,它是低级进程级内存管理之上的内存管理机制. (7认同)
  • @franckspike:不,它会增加到某个点(通常大约4 kB,但这可能会有所不同)然后停止,因为CRT将重新使用以前释放的内存而不是从OS请求新页面. (2认同)