无法使用 GetProcessMemoryInfo 测量静态数组内存使用情况
Posted
技术标签:
【中文标题】无法使用 GetProcessMemoryInfo 测量静态数组内存使用情况【英文标题】:Unable to measure static arrays memory usage with GetProcessMemoryInfo 【发布时间】:2017-03-17 08:38:32 【问题描述】:我正在尝试了解有关内存使用工作的详细信息,以及如何使用 C++ 对其进行测量。我知道在 Windows 下,当包括<Windows.h>
时,一种快速检索当前应用程序进程正在使用的 RAM 量的方法是:
PROCESS_MEMORY_COUNTERS info;
GetProcessMemoryInfo( GetCurrentProcess( ), &info, sizeof(info) );
(uint64_t)info.WorkingSetSize;
然后,我用它来运行一个非常简单的测试:
#include <iostream>
#include <Windows.h>"
int main(void)
uint64_t currentUsedRAM(0);
PROCESS_MEMORY_COUNTERS info;
GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info));
currentUsedRAM = info.WorkingSetSize;
const int N(1000000);
int x[N]; //in the second run, comment this line out
int y[N]; //in the second run, comment this line out
//int *x = new int[N]; //in the second run UNcomment this line out
//int *y = new int[N]; //in the second run UNcomment this line out
for (int i = 0; i < N; i++)
x[i] = 1;
y[i] = 2;
GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info));
currentUsedRAM = info.WorkingSetSize - currentUsedRAM;
std::cout << "Current RAM used: " << currentUsedRAM << "\n";
return 0;
当我运行上面的代码时,我完全不明白,输出是:Current RAM used: 0
,而我期待大约 8mb,因为我填充了两个 1D int
数组,每个数组有 100 万个条目。现在,如果我重新运行代码但使 x
和 y
成为动态分配的数组,那么现在的输出正如预期的那样:Current RAM used: 8007680
。
这是为什么呢?如何让它在这两种情况下检测内存使用情况?
【问题讨论】:
我很惊讶您的程序甚至启动了,因为您在堆栈上为两个数组分配了近 8 兆的内存。 Windows 上的默认堆栈大小通常是单个 MB。有了这个,你还应该得到一个关于为什么你没有得到预期结果的提示。 @Someprogrammerdude 正是让我产生了疑问。我的直觉恰恰是该函数只测量堆上的内存分配,而不是堆栈上的内存分配。但是,由于应用程序运行,我无法理解发生了什么。因此,只是该函数仅获取堆内存使用量。有没有办法计算堆栈内存使用量? 编译优化了这两个数组。你可以做一些副作用来防止这种情况:尝试输出它们元素的总和。 【参考方案1】:编译器已优化您的代码。事实上,对于您的第一次运行,既没有分配 x 也没有分配 y。考虑到有明显的副作用:GetProcessMemoryInfo 的返回值,这种优化似乎有点奇怪。
无论如何,您可以通过添加一些其他副作用来防止这种情况,例如输出这两个数组的每个元素的总和,这将保证崩溃。
为具有自动存储持续时间的本地对象分配内存发生在at the beginning of the enclosing code block and deallocated at the end。因此,您的代码无法测量 main 中任何自动存储持续时间变量的内存使用情况(也无法测量我已删除的代码 sn-p,我不知道)。但是对于那些具有动态存储持续时间的对象来说,情况就不同了,它们是根据请求分配的。
我为评论区的讨论设计了一个涉及回避的测试。您可以看到,如果程序更深入,内存使用量会增加。这证明它计算了堆栈上的内存使用量。顺便说一句,这不是计算您的对象需要多少内存,而是您的程序需要多少。
void foo(int depth, int *a, int *b, uint64_t usage)
if (depth >= 100)
return ;
int x[100], y[100];
for (int i = 0; i < 100; i++)
x[i] = 1 + (a==nullptr?0:a[i]);
y[i] = 2 + (b==nullptr?0:b[i]);
PROCESS_MEMORY_COUNTERS info;
GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info));
std::cout << "Current RAM used: " << info.WorkingSetSize - usage << "\n";
foo(depth+1,x,y,usage);
int sum = 0;
for (int i=0; i<100; i++)
sum += x[i] + y[i];
std::cout << sum << std::endl;
int main(void)
uint64_t currentUsedRAM(0);
PROCESS_MEMORY_COUNTERS info;
GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info));
currentUsedRAM = info.WorkingSetSize;
foo(0, nullptr, nullptr, currentUsedRAM);
return 0;
/*
Current RAM used: 0
Current RAM used: 61440
Current RAM used: 65536
Current RAM used: 65536
Current RAM used: 65536
Current RAM used: 65536
Current RAM used: 69632
Current RAM used: 69632
Current RAM used: 69632
Current RAM used: 69632
Current RAM used: 69632
Current RAM used: 73728
*/
系统每次分配4k,即一页大小。我不知道为什么它会变成 0,然后突然变成 61440。解释 windows 如何管理内存非常困难,而且远远超出了我的能力,尽管我对 4k 的东西很有信心......而且它确实计算了内存使用量对于具有自动存储期限的变量。
【讨论】:
我猜改变 N 不会改变当前使用的 RAM 是因为堆栈的大小是固定的。 我不这么认为。尝试将循环的迭代次数从 1 更改为在堆栈中可以达到的高度(即大约 250000)。您将看到使用的 RAM 量没有改变。您正在捕获的 RAM 与创建的数组无关。数组不计算在内,因为它都在堆栈和函数中,我猜只计算堆内存。由于调用了非常昂贵的std::cout
,您获得的 RAM 使用量完全是由于。如果您注释掉其他所有内容并只留下std::cout << 1 << std::endl
,您将获得相同的 RAM 使用率。
(抱歉,我在尝试编辑时不小心删除了第一条评论。但现在我对我在其中所说的话充满信心,因为正如您在上面的新评论中看到的那样,我已经对其进行了测试。按照我刚才说的,你会看到)以上是关于无法使用 GetProcessMemoryInfo 测量静态数组内存使用情况的主要内容,如果未能解决你的问题,请参考以下文章