C++:从程序、Windows 和 Linux 中测量内存使用情况 [重复]

Posted

技术标签:

【中文标题】C++:从程序、Windows 和 Linux 中测量内存使用情况 [重复]【英文标题】:C++: Measuring memory usage from within the program, Windows and Linux [duplicate] 【发布时间】:2017-06-09 09:16:50 【问题描述】:

看,我想测量我的 C++ 程序的内存使用情况。从程序内部,无需分析器或进程查看器等。

为什么是在程序内部?

    测量将进行数千次——必须自动化;因此,关注Task Managertop,无论如何,都行不通 在生产运行期间进行测量—性能下降(可能由分析器引起)是不可接受的,因为运行时间已经不可忽略(对于大型问题实例需要几个小时)

注意。为什么要测量? 测量已用内存(由操作系统报告)而不是提前计算“预期”使用量的唯一原因是我不能直接分析“sizeof”多少我的主要数据结构是否使用。结构本身是

unordered_map<bitset, map<uint16_t, int64_t> >

这些都被打包到 vector 中(list 实际上也足够了,我只需要访问“相邻”结构;没有有关内存使用的详细信息,我几乎无法决定哪个选择)

vector< unordered_map<bitset, map<uint16_t, int64_t> > >

因此,如果有人知道如何“调整”这种结构占用的内存,那也可以解决问题(尽管我可能不得不提出问题或其他问题)。

环境: 可以假设程序在给定的机器上单独运行(当然还有操作系统等;PC 或超级计算机的节点);它肯定是唯一需要大量(例如 > 512 MiB)内存的程序——计算实验环境。该程序可以在我的家用 PC(16GiB RAM;Windows 7 或 Linux Mint 18.1)或机构超级计算机的节点(大约 100GiB RAM,CentOS 7)上运行,并且该程序可能希望消耗所有这些内存。 注意,超级计算机有效地禁止了用户进程的磁盘交换,而我的家用 PC 有一个较小的页面文件。

内存使用模式。该程序可以说是按顺序填充一个表格,其中每一行是上面指定的vector<...>。假设主要数据结构称为supp。然后,对于每个整数k填充supp[k],需要来自supp[k-1] 的数据。当supp[k] 被填充时,它用于初始化 supp[k+1]。因此,每一次,thisprevnext“表格行”都必须易于访问。填表后,程序在表中进行相对快速的(与“初始化”和填表相比)、非穷举搜索,通过该搜索获得解决方案。 注意内存只通过STL容器分配,我自己从来没有明确new()malloc()

问题。一厢情愿。

    从源代码内部测量进程的总内存使用(包括交换到磁盘)的适当方法是什么(一种用于 Windows,一种用于 Linux) ? 应该是另一个问题,或者更确切地说是一个很好的谷歌搜索,但仍然---明确控制(比如鼓励或阻止)交换到磁盘的正确(或简单)方法是什么?非常欢迎指向有关该主题的权威书籍。再次,原谅我的无知,我想在“永远不要交换supp”或 “交换supp[10]”;然后,当我需要它时,“取消交换supp[10]”——全部来自程序代码。我想我必须解决序列化数据结构并将它们显式存储为二进制文件,然后反转转换。

在 Linux 上,通过 sbrk(0) 捕获堆指针,将它们转换为 64 位无符号整数,并在分配内存后计算差异,这种方法产生了合理的结果(没有做更严格的测试)。

edit 5. 删除了对HeapAlloc wrangling 的引用——无关紧要。

编辑 4. Windows 解决方案 这段代码报告了与任务管理器中的工作集匹配的工作集;这就是我想要的一切——在 Windows 10 x64 上进行了测试(通过 new uint8_t[1024*1024] 之类的分配进行测试,或者更确切地说,new uint8_t[1ULL << howMuch],尚未在我的“生产”中进行测试)。 在 Linux 上,我会尝试 getrusage 或其他类似的东西。 正如@IInspectable 和@conio 所建议的,主要元素是GetProcessMemoryInfo

#include<Windows.h>
#include<Psapi.h>
//get the handle to this process
auto myHandle = GetCurrentProcess();
//to fill in the process' memory usage details
PROCESS_MEMORY_COUNTERS pmc;
//return the usage (bytes), if I may
if (GetProcessMemoryInfo(myHandle, &pmc, sizeof(pmc)))
    return(pmc.WorkingSetSize);
else
    return 0;

edit 5. 删除了对GetProcessWorkingSetSize 的不相关引用。谢谢@conio。

【问题讨论】:

虚拟内存相当复杂。您希望衡量什么特定的统计数据? 我想要最接近 RAM 使用率的值,正如任务管理器“为单个进程保留的总物理内存”或顶部所报告的那样。我不打算爬进虚拟内存,应该报告RAM的使用情况。 对于 Windows,请查看 Process Memory Usage Information。此外,您的程序不消耗 RAM。它消耗地址空间。 RAM 只是一种性能优化。 如果你假装虚拟内存的复杂性不存在,那么我怀疑你会得到很大的帮助。你将如何处理这些信息。它将通知哪些决定? 内存使用决定了给定的问题实例是否可以解决(实际的相关统计数据是每个状态的平均内存使用量,通过将内存使用量除以状态数获得)。它还可能影响程序内部结构的选择(我无法“分析地”计算std::unordered_map&lt;...&gt; 的内存使用量,所以我决定去经验。 【参考方案1】:

在 Windows 上,GlobalMemoryStatusEx 函数为您提供有关您的进程和整个系统的有用信息。

基于this table,您可能希望查看MEMORYSTATUSEX.ullAvailPhys 来回答“我是否即将达到交换开销?”并更改 (MEMORYSTATUSEX.ullTotalVirtual – MEMORYSTATUSEX.ullAvailVirtual) 以回答“我的进程分配了多少 RAM?”

【讨论】:

【参考方案2】:

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

What is private bytes, virtual bytes, working set? How to interpret Windows Task Manager? 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。

我怀疑这是您做出决定的更好指标。

【讨论】:

我相信他担心他的程序会耗尽内存,基于“程序本身肯定喜欢它的 RAM(动态编程,要存储的大量状态),它会很乐意在某些情况下吃掉几个 GiB问题实例......如果问题吞噬了所有可用的 RAM,它将终止——由于交换开销,虚拟内存将毫无用处。” 我不反对,但我的回答——监控页面错误而不是内存使用的建议——不管他是机器上唯一的人还是他关心其他程序是否能够工作都成立也是。 同意页面错误是问题所在,但速率(每次错误数)可能没有那么有用,因为抖动和 I/O 争用。测量(每次计算的故障数)会好得多,因为它不会因故障导致的减速而失败。 所以答案可能是私有工作集;考虑到环境,我认为 shared 可以忽略不计(尽管我更喜欢上限——整个工作集,以防万一)。现在,我真正主要关心的是 实际内存使用情况;另外,据我测试,只要 RAM 用完,程序就会被系统杀死。这很适合我,但是,我会很高兴知道如何在程序自己的日志中报告它何时发生。 @BenVoigt:原则上你是对的。在实践中,我认为你得到那么多你甚至不能执行导致 PFs 的代码之前,你会导致 PFs 上升。每秒。 Process Explorer 和 Process Hacker 等工具显示“PF Delta”,但我不知道有一个性能计数器可以为您提供到目前为止的 PF 数量(而不是速率)。 Process Hacker 是开源的,因此您可以找到NtQueryInformationProcess(与ProcessVmCounters)和NtQuerySystemInformation(与NtQuerySystemInformation)的未记录用途,以分别获取进程和系统PF 计数。

以上是关于C++:从程序、Windows 和 Linux 中测量内存使用情况 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

在 Windows 和 Linux 中运行 C++ 程序

如何把程序从windows平台移植到linux平台

在 Windows 和 Linux 下开发的 C++ 程序的区别

是否有一种标准方法来捕获适用于 linux 和 windows 的 c++ 应用程序中的键盘输入?

在 Windows 7 中交叉编译 C 和 C++ 应用程序,在 linux 下使用 MinGW

使用 pipe() 和 fdopen() 将数据从 Python 脚本传递到 Windows 中的 C++ 应用程序