堆栈内存未释放

时间:2015-12-15 08:03:49

标签: c++ memory memory-management

我有以下循环,从这里的实现中弹出一个C ++并发队列。 https://juanchopanzacpp.wordpress.com/2013/02/26/concurrent-queue-c11/

while (!interrupted)
{
    pxData data = queue->pop(); 
    if (data.value == -1)
    { 
        break; // exit loop on terminating condition
     }
    usleep(7000); // stub to simulate processing
}

我正在使用CentOS7中的系统监视器查看内存历史记录。 在读取队列中的值之后,我试图释放队列占用的内存。但是,随着以下while循环运行,我不会看到内存使用率下降。我已经确认队列长度确实下降了。

但是,当遇到-1并且循环退出时,确实会失效。 (程序仍在运行)但我无法做到这一点,因为在我们睡觉的地方,我想做一些密集的处理。

问题:为什么数据占用的内存不会被释放? (根据系统监视器)当变量超出范围时,堆栈分配的内存不应该被释放吗?

结构定义如下,并在程序开头填充。

typedef struct pxData
{
  float value; // -1 value terminates the loop
  float x, y, z;
  std::complex<float> valueData[65536];
} pxData;

它填充了~10000 pxData,大致翻译为5GB。系统只有~8GB。 因此,在系统中进行其他处理时,内存可以自由编辑,这一点非常重要。

2 个答案:

答案 0 :(得分:6)

这里有一些事情可以发挥作用。

虚拟内存

首先,你需要明白,因为你的程序是&#34;使用&#34; 5 GB的内存并不意味着其他程序只剩下3 GB的RAM。虚拟内存意味着那些5 GB可能只有1 GB的实际&#34;驻留&#34;数据,其他4 GB实际上可能在磁盘上,而不是在RAM中。因此,重要的是要了解常规设置大小&#34;而不是&#34;虚拟尺寸&#34;当你在看你的节目时。请注意,如果您的系统实际上在RAM上运行不足,那么操作系统可能会缩小某些程序的RSS,以及#34;分页&#34;他们的一些记忆。所以不要过于担心&#34; 5 GB&#34;出现在系统监视器中 - 担心是否存在真正的具体性能问题。

堆分配

第二个方面是您从队列中删除项目时虚拟大小不会减少的原因。我们可以猜测,您可以通过逐个mallocnew创建它们,然后将它们推送到队列的后面,将这些元素放入队列中。这意味着您分配的第一个元素将首先从队列中出来。而这反过来意味着当你耗尽了90%的队列时,你的内存分配可能如下所示:

[program|------------------unused-------------------|pxData]

这里的问题是,在现实世界中,仅仅因为你freedelete某事并不意味着操作系统会立即回收那些记忆。实际上,它可能无法收回任何未使用的跨度,除非它们位于&#34; end&#34; (即最近分配的)。由于C ++没有垃圾收集,并且在未经您同意的情况下无法在内存中移动项目,因此您最终会遇到这个重要的漏洞&#34;在你的程序的虚拟内存中。该漏洞将用于满足未来的内存分配请求,但如果您还没有,那么它只是坐在那里,直到队列完全为空:

[program|------------------unused--------------------------]

然后系统能够缩小您的虚拟地址空间:

[program]

它将您带回到您开始的地方。

解决方案

如果你想&#34;修复&#34;这个,一个选项是在&#34;反向&#34;中分配你的记忆,即把最后的项目分配到队列的前面。

另一个选择是通过mmap为队列分配元素,例如, Linux将自动执行大型分配。&#34;您可以通过使用M_MMAP_THRESHOLD调用mallopt(3)并将其设置为比结构大小稍小一些来更改此阈值。这使得分配彼此独立,因此OS可以单独回收它们。这种技术甚至可以应用于现有程序而无需重新编译,因此如果您需要在无法修改的程序中解决此问题,这通常很有用。

答案 1 :(得分:4)

C ++实现会调用某些operator delete来释放动态分配(使用一些operator new)内存。在多个C ++标准库中,new调用mallocdelete调用free

(我主要关注Linux的观点,但原则在其他操作系统上类似)

malloc(或::operator new有时通过系统调用向操作系统内核询问更多内存,更改virtual address space mmap(2)free(或::operator delete经常只是将已发布的内存区域标记为将来malloc的调用重新可用(或new

所以从内核的角度来看(例如,见/proc/,见proc(5) ...),虚拟地址空间没有变化,内存仍然消耗,即使在内部应用程序将其标记为“已释放”,并将在以后的某个分配中重复使用(通过将来调用mallocnew

大多数C ++标准containers使用堆数据内部。特别是您的本地(堆栈分配)std::mapstd::vector(或std::deque)变量调用new&amp;内部数据delete

顺便说一句,我发现你的声明很奇怪。除非每个 struct pxData 完全 65536 使用 valueData广告位,否则我建议使用一些std::vector

  std::vector<std::complex<float>> valueData;

并相应地改进您的代码。您可能需要执行一些valueData.reserve(somesize);和/或valueData.resize(somesize);和/或valueData.push_back(somecomplexnumber);等等。