【问题标题】:How can I make sure the std::vector allocated memory give back to operating system after deallocating?如何确保 std::vector 分配的内存在解除分配后归还给操作系统?
【发布时间】:2015-01-24 06:42:44
【问题描述】:

下面的代码调用foo 并使用while(1) 观察内存使用情况。据我所知,在“完成”打印后,var d 被释放,STL 容器将自行释放数据空间(堆)。

#include <vector>
#include <string>
#include <iostream>

void foo() {
  std::vector<std::string> d(100000000);
  for(int i = 0; i < 100000000; ++i) d[i] = "1,1,3";
  d.resize(0);
  d.shrink_to_fit();
}

int main(int argc, char *argv[])
{
  foo();
  std::cout << "finished" << std::endl;
  while(1) {;}
  return 0; 
}

但是我观察到的(使用htop):内存没有释放回操作系统。这只是一个板凳和与MESOS相关的真实代码,每个进程都有内存限制。

我已经在带有 glibc 2.15 的 linux 服务器上尝试了多个版本的编译器,例如 g++-4.7.2 g++-4.8.1、clang++。此外,我也使用 tcmalloc 而不是默认的 malloc,但它仍然不起作用(在 MAC 机器上不会发生问题)。

有什么问题?如何确保内存回馈给操作系统? 谢谢。

【问题讨论】:

  • 其他人或许可以在标准中指出,但基于this页面delete只需释放内存,未指定必须将其返回给操作系统离开。如果您想保证这一点,您可能需要编写自己的newdelete 版本,它们使用您操作系统的函数调用并确保内存实际返回给操作系统。

标签: c++ memory stl operating-system glibc


【解决方案1】:

如何确保内存回馈给操作系统?

你可以终止你的进程。

有什么问题?

可能没有。程序不返回内存是正常的(尽管对于一些特别大的分配,Linux 确实会提前返回内存)。他们通常使用sbrk 或等效的来增加他们可用的虚拟地址空间,但通常不值得尝试返回已释放的内存。这可能违反直觉,但它也被证明在数十年内对数百万个程序是可行的,所以除非你有一个具体的切实问题,否则你不应该为此烦恼。它不应该给您带来问题,因为当应用程序执行进一步分配时,释放的内存将被重用,因此您提到的“每个进程的 MESOS 内存限制”仍然会影响最大瞬时内存使用量的“高水位线”同样的方式。

请注意,支持virtual memory 的操作系统可能会将长时间未使用的已释放页面交换到磁盘,以便内核或其他应用程序重用后备 RAM。

也可以使用例如手动控制它。内存映射文件,但是编写这样的分配器并使用标准容器是一项艰巨的任务......关于如何解决该问题的许多其他 SO 问题。

【讨论】:

    【解决方案2】:

    从操作系统分配内存有两个缺点:

    1. 高开销。系统调用涉及切换到保护模式,这比简单的函数调用需要更长的时间,然后操作系统本身的内存管理可能相当复杂。
    2. 高粒度。操作系统可能具有最小大小分配,例如 4K。对于一个 6 字节的字符串来说,这是一个很大的开销。

    由于这些原因,C++ 内存分配器只会向操作系统询问大块,然后在通过newmalloc 询问时将其分块。

    当这些内存被释放时,它们会被放回池中,以便在下一次请求时再次分发。现在,一个较大块的所有块很有可能最终被释放,但在现实生活中这种情况发生的频率如何?有可能每个块至少有一个分配会持续很长时间,从而阻止该块返回给操作系统。如果它返回,你认为程序会在短时间内返回并再次请求它的可能性有多大?实际上,将块返回给操作系统通常是不值得的。您的测试程序是一个高度人为的案例,不值得优化。

    【讨论】:

      【解决方案3】:

      在大多数现代系统中,操作系统以页为单位管理内存。应用程序内存由库函数在池(堆)中管理。当您的应用程序分配内存时,库函数会尝试查找您请求大小的可用块。如果内存不在池中,则库调用系统向进程添加更多页面以合并到池(堆)中。当您释放内存时,它会回到池中。池中分配的页面不会返回给操作系统。

      【讨论】:

        猜你喜欢
        • 2016-08-06
        • 1970-01-01
        • 2021-10-16
        • 2017-07-11
        • 1970-01-01
        • 2012-10-29
        • 1970-01-01
        • 1970-01-01
        • 2020-10-11
        相关资源
        最近更新 更多