我有以下循环,它弹出一个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::complexvalueData[65536]; } pxData;
它填充了~10000 pxData,大致翻译为5GB.系统只有~8GB.因此,为了在系统中进行其他处理,内存可以自由编辑.
这里有一些事情在起作用.
首先,您需要了解,仅仅因为您的程序"使用"5 GB的内存并不意味着其他程序只剩下3 GB的RAM.虚拟内存意味着那些5 GB可能只有1 GB的实际"驻留"数据,而另外4 GB实际上可能在磁盘而不是RAM中.因此,当您查看程序时,查看"常驻设置大小"而不是"虚拟大小"非常重要.请注意,如果您的系统实际上在RAM上运行不足,操作系统可能会通过"分页"部分内存来缩小某些程序的RSS.因此,不要过于担心系统监视器中出现"5 GB" - 如果您遇到真正的具体性能问题,请担心.
第二个方面是您从队列中删除项目时虚拟大小不会减少的原因.我们可以猜测,您可以通过使用malloc
或new
逐个创建它们将这些元素放入队列,然后将它们推送到队列的后面.这意味着您分配的第一个元素将首先从队列中出来.而这反过来意味着当你耗尽了90%的队列时,你的内存分配可能如下所示:
[program|------------------unused-------------------|pxData]
这里的问题是,在现实世界中,仅仅因为你free
或者delete
其他东西并不意味着操作系统会立即回收那些记忆.实际上,它可能无法回收任何未使用的跨度,除非它们处于"结束"(即最近分配的).由于C++没有垃圾收集,并且在未经您同意的情况下无法在内存中移动项目,因此您最终会在程序的虚拟内存中出现这个"漏洞".该漏洞将用于满足未来的内存分配请求,但如果您还没有,它只是坐在那里,直到队列完全为空:
[program|------------------unused--------------------------]
然后系统能够缩小您的虚拟地址空间:
[program]
这将带您回到您的起点.
如果你想"修复"这个,一个选择是以"反向"分配你的内存,即将最后的项目分配到队列的前面.
另一个选择是为队列分配元素mmap
,例如Linux将自动执行"大"的分配.您可以通过调用改变这个门槛mallopt(3)
与M_MMAP_THRESHOLD
和设置它比你的结构尺寸小一点点.这使得分配彼此独立,因此OS可以单独回收它们.这种技术甚至可以应用于现有程序而无需重新编译,因此如果您需要在无法修改的程序中解决此问题,通常很有用.