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

C++: Measuring memory usage from within the program, Windows and Linux

本文关键字:测量 内存 情况 用情 Linux 程序 Windows C++      更新时间:2023-10-16

看,我想测量C++程序的内存使用情况。从程序内部,没有配置文件或进程查看器等

为什么来自程序内部

  1. 测量将进行数千次——必须自动化;因此,关注Task Managertop,不管怎样,都无济于事
  2. 测量是在生产运行期间进行的——性能下降可能是由轮廓仪引起的,这是不可接受的,因为运行时间已经不可忽略了(对于大型问题实例,需要几个小时)

注意。为什么要测量测量已用内存(如操作系统报告的)而不是提前计算"预期"使用量的唯一原因是,我无法直接分析"sizeof"我的主要数据结构使用了多少。结构本身就是

unordered_map<bitset, map<uint16_t, int64_t> >

这些都被打包到一个vector中,供我使用(list实际上也足够了,我只需要访问"相邻"结构;如果没有内存使用的详细信息,我很难决定选择哪个)

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

因此,如果有人知道如何"确定"这样一个结构所占用的内存的大小,这也会解决问题(尽管我可能不得不解决这个问题)。

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

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

问题。胡思乱想

  1. 从源代码(一个用于Windows,一个用于Linux)内部测量进程总内存使用量的适当方法是什么
  2. 这可能是另一个问题,或者更确切地说是一个很好的谷歌搜索会话,但仍然——明确控制(比如鼓励或劝阻)交换到磁盘的正确(或简单)方法是什么?如果能找到一本关于这个问题的权威书籍,那将是非常受欢迎的。再次,请原谅我的无知,我想用一种方式说一些类似"永远不要交换supp"或"交换supp[10]";然后,当我需要它时,"unscapsupp[10]"——所有这些都来自程序的代码。我想我必须下定决心序列化数据结构,并将其显式存储为二进制文件,然后反转转换

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

编辑5.删除了对HeapAlloc争论的引用--无关。

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

#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;

编辑5.删除了对GetProcessWorkingSetSize的引用,认为其不相关。谢谢@conio。

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

根据此表,您可能需要查看MEMORYSTATUSEX.ullAvailPhys以回答"我即将达到交换开销吗?",并查看(MEMORYSTATUSEX.ullTotalVirtual – MEMORYSTATUSEX.ullAvailVirtual)中的更改以回答"进程分配了多少RAM?">

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

参见

  • 什么是私有字节、虚拟字节、工作集
  • 如何解释Windows任务管理器
  • https://blogs.msdn.microsoft.com/tims/2010/10/29/pdc10-mysteries-of-windows-memory-management-revealed-part-two/

了解术语和更多细节。

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

(你也可以使用QueryWorkingSet(Ex)并自己计算,但在我看来,这太糟糕了。你可以使用GetProcessMemoryInfo获得(非私有)工作集。)


但更有趣的问题是,这是否有助于您的程序做出有用的决策。如果没有人要求或使用内存,那么你使用大部分物理内存这一事实就无关紧要了。或者你担心你的程序会占用太多内存?

你还没有提到它使用的算法或内存使用模式。如果它使用大量内存,但主要是按顺序进行,并且很少返回到旧内存,那么这可能不是问题。Windows急切地将"旧"页面写入磁盘,然后完全需要调出驻留页面来满足物理内存的需求。如果一切顺利,将这些已经写入磁盘的页面重新用于其他用途是非常便宜的。

如果你真正关心的是内存抖动("由于交换开销,虚拟内存将毫无用处"),那么这就是你应该寻找的,而不是试图从使用的物理内存量中推断(或猜测…)。一个更有用的度量标准是每单位时间的页面错误。碰巧也有性能计数器。请参阅,例如评估内存和缓存使用情况。

我怀疑这是一个更好的衡量标准,以你的决定为基础。