ChatGPT解决这个技术问题 Extra ChatGPT

什么是私有字节、虚拟字节、工作集?

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

perfmon 是这样解释这些术语的:

工作集是此进程的工作集的当前大小(以字节为单位)。工作集是进程中的线程最近接触的内存页集。如果计算机中的可用内存高于阈值,则页面将留在进程的工作集中,即使它们没有被使用。当可用内存低于阈值时,将从工作集中修剪页面。如果需要它们,它们将在离开主存储器之前被软故障返回到工作集中。

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

Private Bytes 是当前进程分配的不能与其他进程共享的内存大小(以字节为单位)。

这些是我的问题:

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

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

Private Bytes、Working Set 和 Virtual Bytes 之间有什么关系吗?

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

更好的工具是 valgrind/helgrind,但不幸的是在 Windows 下不是:(
我是否应该测量私有字节以确定进程是否有任何泄漏如果进程的私有字节没有增长,那么你就没有内存泄漏。如果它们增长,可能是由于内存泄漏,也可能是由于内存碎片。我认为很难说查看私有字节的增长究竟意味着什么。
@SergeiKurenkov 我们可以说的一件事是,它永远不会是由于“内存碎片”造成的。

C
Community

对这个问题的简短回答是,这些值都不是可执行文件实际使用多少内存的可靠指标,而且它们都不适合调试内存泄漏。

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

工作集是指进程使用的总物理内存(RAM)。但是,与私有字节不同,这还包括内存映射文件和各种其他资源,因此它的测量精度甚至不如私有字节。这与任务管理器的“内存使用情况”中报告的值相同,并且近年来一直是无数混乱的根源。工作集中的内存是“物理的”,因为它可以在没有页面错误的情况下被寻址;但是,备用页面列表仍然物理上位于内存中,但未在工作集中报告,这就是为什么您在最小化应用程序时可能会看到“Mem Usage”突然下降的原因。

Virtual Bytes 是整个进程占用的总虚拟地址空间。这就像工作集,从某种意义上说,它包括内存映射文件(共享 DLL),但它还包括备用列表中的数据和已经被分页并位于磁盘某处的页面文件中的数据。在重负载下,系统上每个进程使用的总虚拟字节数加起来会比机器实际拥有的内存多得多。

所以关系是:

Private Bytes 是您的应用实际分配的,但包括页面文件的使用;

工作集是非分页私有字节加上内存映射文件;

虚拟字节是工作集加上分页的私有字节和备用列表。

这里还有另一个问题;正如共享库可以在您的应用程序模块内分配内存,从而导致在您的应用程序的私有字节中报告潜在的误报,您的应用程序也可能最终在共享模块内分配内存,从而导致误报。这意味着您的应用程序实际上可能存在根本不会在私有字节中表现出来的内存泄漏。不太可能,但可能。

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

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

我希望这能解决一些问题!跟踪内存泄漏是调试中最困难的事情之一。祝你好运。


恐怕你的回答不太正确。私有字节是指进程可执行文件要求的内存量(RAM) - 不仅仅是物理内存。因此,您肯定可以通过监视私有字节来检查大多数内存泄漏情况。尝试 ::VisualAlloc 提交一大块内存(比如 1.5G)。您应该能够看到您的私有字节比工作集大得多。这证明您的“工作集是私有字节加上内存映射文件”是不正确的。
实际上,我相信写的理解是“工作集是内存中的私有字节加上内存映射文件”。并且可以换出私有字节 - 您可以看到大于机器中物理内存的私有字节。
@Aaronaught:您关于可靠指标和适合调试的第一个陈述令人困惑。私有字节是应用程序内存空间泄漏的可靠指标。它可能是依赖 DLL 和间接的,但它是应用程序内存空间中的泄漏。你能解释为什么它不能用于调试吗?应用程序进程的完整内存转储应该告诉我们什么正在消耗该内存。我不确定我理解为什么它不能用于调试。你能解释一下吗?
运行完整的 !objsize,这应该会显示直接堆中的所有固定对象。您可以通过检查 eeheap -gc 来确认。这应该会告诉您音量卡在哪里。通常,如果上述所有命令都没有可用的提示,则您的私有字节将被 GC 中未收集的对象消耗。现在继续讨论 gchandles 或 gcleaks。这些命令应该告诉你哪些类型/对象地址不能被映射。指针还在,但对象不见了。对于未发布的事件处理程序来说,这是一个非常明确的问题。
如果您正在进行 .NET 开发,我过去曾使用过一个非常好的工具来实际查找内存泄漏的来源,那就是 RedGate 软件的 ANTS 内存分析器。它将准确地显示哪些对象保留在内存中。您仍然需要知道哪些不应该在内存中,以及采取哪些步骤来确保它们不存在,而只是告诉您保留的内容通常足以弄清楚。
r
riQQ

perfmon 计数器的定义从一开始就被打破,并且由于某种原因似乎很难纠正。

MSDN 上的视频“Mysteries of Memory Management Revealed”中提供了对 Windows 内存管理的一个很好的概述:它涵盖了比跟踪内存泄漏所需的更多主题(例如工作集管理),但在相关主题中提供了足够的详细信息。

为了让您了解 perfmon 计数器描述的问题,这里是关于 MSDN 上“Private Bytes Performance Counter -- Beware!”的私有字节的内幕:

问:什么时候私有字节不是私有字节? A:当它不是居民时。 Private Bytes 计数器报告进程的提交费用。也就是说,在交换文件中已分配的空间量,用于在私有内存被换出时保存私有内存的内容。注意:我避免使用“保留”一词,因为可能与未提交的保留状态下的虚拟内存混淆。

来自 MSDN 上的“Performance Planning”:

3.3 私有字节 3.3.1 描述 私有内存,被定义为分配给一个进程的内存,不能被其他进程共享。当在一台机器上执行多个此类进程时,此内存比共享内存更昂贵。 (传统的)非托管 dll 中的私有内存通常由 C++ 静态构成,并且大约占 dll 总工作集的 5%。


投票是因为关于它是如何被破坏的非常好的例子!
第一个引用是错误的。分配“私有字节”不需要“在交换文件中分配”(实际上称为页面文件)。您甚至不必有一个页面文件来分配“私有字节”。事实上,分配私有字节不会立即使用任何地方的任何空间,并且可能永远不会使用分配的那么多空间。
第二个报价也好不到哪里去。 DLL 代码中使用的私有字节不一定大部分是在 DLL 中静态分配的。 DLL 代码可以完全自由地调用 VirtualAlloc、HeapAlloc(CRTL 中的 malloc 和 new)等。它还试图将私有内存大小描述为工作集大小的百分比,这是荒谬的。前者是虚拟大小(对于每次使用具有相同输入的代码来说都是相同的),而后者是物理大小(从一次运行到下一次运行可能完全不同,取决于有多少内存丰富或 -饿死机器了)。
S
Stephen Kellett

您不应该尝试使用 perfmon、任务管理器或任何类似的工具来确定内存泄漏。它们有助于识别趋势,但仅此而已。他们以绝对值报告的数字过于模糊和汇总,无法用于特定任务,例如内存泄漏检测。

之前对这个问题的回答已经很好地解释了各种类型是什么。

你问一个工具推荐:我推荐 Memory Validator。能够监控进行数十亿内存分配的应用程序。

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

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


我什至不能运行一个简单的类文件(在 Java 中)?是什么赋予了?
我怀疑斯蒂芬和魔鬼在某种程度上是相关的,甚至是克隆的...... :D ;)
@StephenKellett,有试用版吗?
@Pacerier 如果您点击链接,则在页面左侧的购买选项上方有 x86 和 x64 版本的试用版。
m
mcanti

这里有一个有趣的讨论:http://social.msdn.microsoft.com/Forums/en-US/vcgeneral/thread/307d658a-f677-40f2-bdef-e6352b0bfe9e/ 我对这个线程的理解是,释放小分配不会反映在 Private Bytes 或 Working Set 中。

长话短说:

如果我打电话

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

那么 Private Bytes 只反映分配,而不是释放。

如果我打电话

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

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


这可以通过 C 标准库内存函数使用自定义或 Win32 堆这一事实来解释,这是一种在低级进程级内存管理之上的内存管理机制。
@Kyberias,那么我们如何做到这一点?
而(1)免费(malloc(1000)); // 这会导致私有字节数永远增加吗?
@franckspike:不,它会增加到某个点(通常约为 4 kB,但这可能会有所不同)然后停止,因为 CRT 将重新使用先前释放的内存,而不是从操作系统请求新页面。
@Pacerier:您可以调用 VirtualAlloc 和 VirtualFree。