堆栈内存未释放 我有下面的循环,它从这里的实现中弹出C++并发队列。p>
我正在使用CentOS7中的系统监视器查看内存历史记录。 在从队列读取值之后,我试图释放队列占用的内存。然而,随着下面的while循环的运行,我没有看到内存使用率下降。我已经验证了队列长度确实下降了 但是,当遇到-1并且循环退出时,它确实会下降。(程序仍在运行)但我不能有这个,因为在usleep所在的地方,我想做一些密集处理 问题:为什么数据占用的内存没有释放出来?(根据系统监视器)当变量超出范围时,堆栈分配的内存不应该被释放吗 结构定义如下,并在程序开始时填充堆栈内存未释放 我有下面的循环,它从这里的实现中弹出C++并发队列。p>,c++,memory,memory-management,C++,Memory,Memory Management,我正在使用CentOS7中的系统监视器查看内存历史记录。 在从队列读取值之后,我试图释放队列占用的内存。然而,随着下面的while循环的运行,我没有看到内存使用率下降。我已经验证了队列长度确实下降了 但是,当遇到-1并且循环退出时,它确实会下降。(程序仍在运行)但我不能有这个,因为在usleep所在的地方,我想做一些密集处理 问题:为什么数据占用的内存没有释放出来?(根据系统监视器)当变量超出范围时,堆栈分配的内存不应该被释放吗 结构定义如下,并在程序开始时填充 typedef struct p
typedef struct pxData
{
float value; // -1 value terminates the loop
float x, y, z;
std::complex<float> valueData[65536];
} pxData;
typedef结构pxData
{
浮点值;//-1值终止循环
浮动x,y,z;
std::复数值数据[65536];
}PX数据;
它填充了约10000像素的数据,大致相当于5GB。系统只有~8GB。
因此,释放内存以便在系统中进行其他处理是很重要的 这里有一些事情在起作用 虚拟内存 首先,您需要了解,仅仅因为您的程序“使用”了5GB内存,并不意味着其他程序只剩下3GB的RAM。虚拟内存意味着这5 GB可能只有1 GB的实际“驻留”数据,而其他4 GB可能实际位于磁盘上,而不是RAM中。因此,在查看程序时,查看“驻留集大小”而不是“虚拟大小”非常重要。请注意,如果您的系统实际运行的RAM不足,操作系统可能会通过“调出”一些程序的内存来缩小它们的RSS。因此,不要太担心系统监视器中出现的“5GB”——如果您有实际的、具体的性能问题,请担心 堆分配 第二个方面是为什么从队列中删除项目时虚拟大小不会减小。我们可以猜测,您通过使用
malloc
或new
逐个创建这些元素,然后将它们推到队列的后面,从而将它们放入队列中。这意味着您分配的第一个元素将首先从队列中出来。这反过来意味着,当您耗尽了队列的90%时,您的内存分配可能如下所示:
[program|------------------unused-------------------|pxData]
这里的问题是,在现实世界中,仅仅因为你免费
或删除
某些东西并不意味着操作系统会立即回收这些内存。事实上,它可能无法回收任何未使用的跨度,除非它们位于“末端”(即最近分配的跨度)。因为C++没有垃圾收集,并且不能在没有你同意的情况下在内存中移动项目,所以你的程序的虚拟内存中会有这个“大洞”。该漏洞将用于满足未来的内存分配请求,但如果没有,它将一直存在,直到队列完全为空:
[program|------------------unused--------------------------]
然后,系统可以缩小虚拟地址空间:
[program]
这让你回到了起点
解决
如果要“修复”此问题,一个选项是以“反向”方式分配内存,即将最后分配的项目放在队列的前面
另一个选项是通过
mmap
为队列分配元素,例如Linux会自动为“大”的分配分配元素。您可以通过调用M_mmap_threshold
并将其设置为略小于结构大小来更改阈值。这使得分配相互独立,因此操作系统可以单独回收它们。这种技术甚至可以应用到现有程序中,而不需要重新编译,所以如果你需要在一个程序中解决这个问题,那么C++通常是有用的。 < P>一个C++实现会调用一些<代码>操作符删除< /C> >动态释放(使用一些<代码>操作符new < /C> >内存。在几个C++标准库中,<代码>新< /Calp>调用<代码> Malc C < /C> >和<代码>删除< /代码>调用<代码>免费< /代码> .<
(我关注的是Linux的观点,但原则与其他操作系统类似)
但是,虽然malloc
(或::operator new
)有时会通过系统调用来请求操作系统内核提供更多内存,但free
(或::operator delete
)通常只是将释放的内存区域标记为可供将来调用malloc
(或new
)使用
因此,从内核的角度来看(例如,通过/proc/
,请参阅…),虚拟地址空间没有改变,内存仍在消耗,即使在应用程序内部它被标记为“已释放”,并将在将来的某个分配中重新使用(通过将来调用malloc
或new
)
和大多数C++标准都在内部使用堆数据。特别是您的本地(堆栈分配)
std::map
或std::vector
(或std::deque
)变量将调用new
和delete
,以获取内部数据
顺便说一句,我觉得你的声明很奇怪。除非每个
struct pxData
都使用了65536个valueData
插槽,否则我建议使用一些这样的插槽
std::向量值数据;
并相应地改进代码。您可能需要执行一些
valueData.reserve(somesize)代码>和/或valueData.resize(somesize)代码>和/或值数据。向后推(somecomplexnumber)代码>等…什么时候超出范围usleep
仍在范围内运行。我看不出有任何理由用C
什么是pop.value
?我指的是whil的下一次迭代
[program]
std::vector<std::complex<float>> valueData;