C++:从程序内部测量内存使用情况,Windows和Linux

15 浏览
0 Comments

C++:从程序内部测量内存使用情况,Windows和Linux

你看,我想要测量我的C++程序的内存使用情况,而且是在程序内部进行,而不是使用性能分析器或者进程查看器等工具。\n为什么要从程序内部进行测量呢?\n

    \n

  1. 测量将会进行成千上万次,必须是自动化的;因此,通过观察任务管理器或者top等工具是不可行的。
  2. \n

  3. 测量是在生产运行期间进行的,因此性能下降不可接受,因为运行时间已经相当长了(对于大问题实例来说,可能需要数小时)。
  4. \n

\n注意:为什么要进行测量呢?与提前计算“预期”使用量相比,测量已使用的内存(由操作系统报告)的唯一原因是我无法直接、分析性地“sizeof”我的主要数据结构使用了多少内存。这个结构本身是unordered_map>,对我来说,这些结构被打包到一个vector中(一个list也足够了,因为我只需要访问“相邻”的结构;如果没有关于内存使用情况的详细信息,我几乎无法决定选择哪个)vector>>。因此,如果有人知道如何“sizeof”这样一个结构占用的内存,那也可以解决这个问题(虽然我可能需要提出另一个问题或者其他什么)。\n环境:可以假设该程序在给定的机器上独立运行(当然还有操作系统等);可以肯定的是,这是唯一一个需要大量(大于512 MiB)内存的程序——计算实验环境。该程序要么在我的家用PC上运行(16GiB RAM;Windows 7或Linux Mint 18.1),要么在机构的超级计算机节点上运行(约100GiB RAM,CentOS 7),并且该程序可能希望使用所有的RAM。请注意,超级计算机实际上禁止用户进程的磁盘交换,并且我的家用PC的页面文件很小。\n内存使用模式:可以说该程序顺序填充一种表格,其中每一行都是上述指定的vector。假设主要数据结构被称为supp。然后,对于每个整数k,需要填充supp[k],这时需要使用supp[k-1]的数据。当填充supp[k]时,它被用来初始化supp[k+1]。因此,每次都必须方便地访问到this、prev和next“表格行”。在填充表格后,程序会在表格中进行相对较快(与“初始化”和填充表格相比)的非穷举搜索,通过该搜索获得解决方案。请注意,内存仅通过STL容器进行分配,我从未显式地使用new()或malloc()。\n问题。美好的想法。\n

    \n

  1. 在源代码中测量进程的总内存使用情况(包括交换到磁盘上的内存)的适当方法是什么(一个用于Windows,一个用于Linux)?
  2. \n

  3. 可能应该是另一个问题,或者说是一个很好的谷歌搜索会话,但还是......控制(例如鼓励或阻止)交换到磁盘的适当(或者只是简单)方法是什么?对这个主题的权威书籍的指引将非常受欢迎。再次请原谅我的无知,我想要一种方法来表达“永远不要交换supp”或“交换supp[10]”的意思,然后在需要时“取消交换supp[10]”——所有这些都来自程序的代码。我认为我不得不将数据结构序列化并显式存储为二进制文件,然后反向进行转换。
  4. \n

\n在Linux上,通过sbrk(0)捕获堆指针,将它们强制转换为64位无符号整数,并在内存分配后计算差异似乎是最简单的方法,这种方法产生了合理的结果(尚未进行更严格的测试)。\n编辑5:删除了对HeapAlloc的提及——不相关。\n编辑4. Windows解决方案\n这段代码报告了与任务管理器中匹配的工作集;这正是我想要的——在Windows 10 x64上进行了测试(通过类似于new uint8_t[1024*1024]或者更确切地说,new uint8_t[1ULL << howMuch]进行分配,尚未在我的“产品”中使用)。\n在Linux上,我会尝试使用getrusage或其他方法来获得相应的结果。\n主要元素是GetProcessMemoryInfo,正如@IInspectable和@conio所建议的。\n#include\n#include\n//获取此进程的句柄\nauto myHandle = GetCurrentProcess();\n//填充进程的内存使用情况细节\nPROCESS_MEMORY_COUNTERS pmc;\n//返回使用情况(字节)\nif (GetProcessMemoryInfo(myHandle, &pmc, sizeof(pmc)))\n return(pmc.WorkingSetSize);\nelse\n return 0;\n编辑5:删除了对GetProcessWorkingSetSize的引用,因为它与本题无关。感谢@conio。

0
0 Comments

C++: 在程序内部测量内存使用情况(Windows和Linux)

要知道进程占用了多少物理内存,您需要查询进程的工作集或更有可能的是私有工作集。工作集是指您的进程在RAM中使用的物理页面的数量(或多或少)。私有工作集不包括共享内存。

有关术语和更多详细信息,请参见以下链接:

- [What is private bytes, virtual bytes, working set?](https://stackoverflow.com/questions/1984186)

- [How to interpret Windows Task Manager?](https://stackoverflow.com/questions/1170654)

- [https://blogs.msdn.microsoft.com/tims/2010/10/29/pdc10-mysteries-of-windows-memory-management-revealed-part-two/](https://blogs.msdn.microsoft.com/tims/2010/10/29/pdc10-mysteries-of-windows-memory-management-revealed-part-two/)

这两个指标都有性能计数器。

(您还可以使用QueryWorkingSet(Ex)自己计算,但我认为这很麻烦。您可以使用GetProcessMemoryInfo获取(非私有)工作集。)

但更有意思的问题是,这是否有助于您的程序做出有用的决策。如果没有人请求内存或使用内存,您使用大多数物理内存的事实本身就没有意义。或者您是否担心您的程序独自使用太多内存?

您没有提及它使用的算法或其内存使用模式。如果它使用了大量内存,但大多数情况下是顺序使用,并且相对较少地返回到旧内存,则可能不是问题。Windows会及早将“旧”页面写入磁盘,以便在完全需要提供物理内存的需求时将驻留页面分页出去。如果一切顺利,重用已经写入磁盘的这些页面以供其他用途非常便宜。

如果您真正担心的是内存抖动(“由于交换开销,虚拟内存将毫无用处”),那么这是您应该寻找的,而不是试图从使用的物理内存量中推断(或猜测)出来。更有用的指标是每单位时间的页面故障数。恰好有性能计数器可以用于此。例如,请参见[Evaluating Memory and Cache Usage](https://technet.microsoft.com/en-us/library/cc958290.aspx)。

我怀疑这是一个更好的基于决策的指标。

我确实认为他担心的是他的程序单独耗尽内存,基于“程序本身肯定喜欢它的RAM(动态编程,需要存储许多状态),在某些问题实例中,它会愉快地占用几个GiB的内存...如果问题占用了所有可用的RAM,它就会终止-由于交换开销,虚拟内存将毫无用处。”的说法。

我不反对,但是我的答案-建议监视页面故障而不是内存使用情况-无论他是否是机器上唯一的用户,或者他是否关心其他程序能够正常工作,都是适用的。

同意页面故障是问题,但是速率(每单位时间的故障)可能并不那么有帮助,因为抖动和I/O争用。测量(每计算的故障)将更好,因为它不受故障引起的减速的影响。

所以答案可能是私有工作集;鉴于环境,我假设共享内存可以忽略不计(尽管我更喜欢上限-整个工作集,以防万一)。现在,我真正关心的是实际内存使用情况;此外,据我测试,当RAM耗尽时,系统通常会立即终止程序。这对我来说很合适,但是我将非常高兴知道如何捕捉到这种情况,并在程序自己的日志中进行报告。

在原则上,你是对的。实际上,我认为在你得到这么多页面故障之前,你甚至无法执行导致页面故障的代码,你会引起页面故障的增加。每秒钟。像Process Explorer和Process Hacker这样的工具显示“PF Delta”,但我不知道有没有性能计数器可以给出到目前为止的PF数量(而不是速率)。Process Hacker是开源的,因此您可以找到NtQueryInformationProcess(使用ProcessVmCounters)和NtQuerySystemInformation(使用NtQuerySystemInformation)的未记录用法,分别获取进程和系统的PF计数。

如何捕捉到由于资源不足而终止进程的问题确实应该是一个单独的问题,但解决方案可能是设置未处理的异常过滤器(参见SetUnhandledExceptionFilter)或使用WER(或类似Google Breakpad的东西)。

0
0 Comments

在Windows系统上,使用GlobalMemoryStatusEx函数可以提供有关进程和整个系统的有用信息。根据这个表格,您可能需要查看MEMORYSTATUSEX.ullAvailPhys来回答“我是否接近交换开销的限制?”以及(MEMORYSTATUSEX.ullTotalVirtual - MEMORYSTATUSEX.ullAvailVirtual)的变化来回答“我的进程分配了多少RAM?”

0