c++ - 堆栈内存未释放

标签 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 并退出循环时,它确实会下降。 (程序还在运行)但是我不能有这个,因为usleep在哪里,我想做一些密集的处理。

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

该结构定义如下,并在程序开始时填充。

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

它填充了约 10000 像素数据,大致相当于 5GB。系统只有~8GB。 因此,释放内存用于系统中的其他处理非常重要。

最佳答案

这里有一些事情在起作用。

虚拟内存

首先,您需要了解,仅仅因为您的程序“使用”了 5 GB 的内存并不意味着其他程序只剩下 3 GB 的 RAM。虚拟内存意味着这 5 GB 可能只是 1 GB 的实际“驻留”数据,而其他 4 GB 实际上可能在磁盘上而不是在 RAM 中。因此,在查看程序时,查看“驻留集大小”而不是“虚拟大小”很重要。请注意,如果您的系统实际上运行内存不足,操作系统可能会通过“调出”部分内存来缩小某些程序的 RSS。因此,不要太担心系统监视器中出现的“5 GB”——如果您遇到真实、具体的性能问题,请担心。

堆分配

第二个方面是为什么当您从队列中删除项目时您的虚拟大小不会减少。我们可以猜测,您通过使用 mallocnew 一个一个地创建它们,然后将它们推到队列的后面,将它们放入队列中。这意味着您分配的第一个元素将首先从队列中出来。这反过来意味着当您排空 90% 的队列时,您的内存分配可能如下所示:

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

这里的问题是,在现实世界中,仅仅因为您释放删除 某些内容并不意味着操作系统会立即回收该内存。事实上,它可能无法回收任何未使用的跨度,除非它们处于“末尾”(即最近分配的)。由于 C++ 没有垃圾收集功能,并且未经您的同意不能在内存中四处移动项目,因此您最终会在程序的虚拟内存中遇到这个大“洞”。那个空洞将用于满足 future 的内存分配请求,但如果你没有,它就坐在那里,直到队列完全为空:

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

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

[program]

这会让您回到起点。

解决方案

如果你想“修复”这个问题,一个选择是“反向”分配你的内存,即将分配的最后一个项目放在队列的前面。

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

关于c++ - 堆栈内存未释放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34283840/

相关文章:

c++ - 在 main 之前使用来自不同文件的变量

c++ - 如何提示操作系统哪些内存块不应交换到磁盘?

iphone - 解除分配 UIApplicationDelegate 拥有的对象有什么好处吗?

c++ - 访问 3 索引数组的最快方法

c++ - Windows 7 中的 OLEUnInitialize()

c++ - 内联以汇编语言编写的外部函数

c++ - 为什么我无法覆盖虚拟功能?

c - 由初始化列表初始化的数组存储在哪里?

c++ - 为什么 shared_ptr 签名与数组的 unique_ptr 不同?

C++ - 重载 operator new 并提供额外的参数