【发布时间】:2020-10-14 08:04:19
【问题描述】:
我一直在阅读有关托管语言的零暂停垃圾收集器的一些信息。据我了解,如果没有 stop-the-world 暂停,最困难的事情之一就是堆压缩。只有极少数的收藏家(例如 Azul C4、ZGC)似乎正在这样做,或者至少正在接近这一点。
因此,大多数 GC 引入了可怕的 stop-the-world 会暂停堆的压缩(糟糕!)。不这样做似乎非常困难,并且确实会带来性能/吞吐量损失。所以不管怎样,这一步似乎有点问题。
然而——据我所知,大多数(如果不是全部)GC 仍然偶尔会压缩堆。我还没有看到默认情况下不执行此操作的现代 GC。这让我相信:它必须非常非常重要。如果不是这样,当然,这种折衷是不值得的。
同时,我从未见过有人在 C++ 中进行内存碎片整理。我敢肯定有些人会这样做,但是-如果我错了,请纠正我-这似乎根本不是一个共同的问题。 我当然可以想象静态内存会在一定程度上减少这种情况,但可以肯定的是,大多数代码库都会进行相当多的动态分配?!
所以我很好奇,这是为什么呢?
我的假设(在托管语言中非常重要;在 C++ 中很少这样做)是否正确?如果是,我是否缺少任何解释?
【问题讨论】:
-
你不能在 C++ 中进行堆压缩,因为这会改变人们存储指针的对象的地址。
-
这很重要。长时间运行的 C++ 进程可能而且确实会遭受内存碎片的影响。现代内存分配器(如 tcmalloc 或 jemalloc)试图通过使用多个分配桶来处理相同大小的请求并管理一个空闲列表以确保在向操作系统请求额外内存之前首先填充这些桶中的漏洞,从而防止这些问题。托管语言有这样做的额外动力,因为您的 GC 在标记阶段必须扫描的内存页越少,它运行得越快。
-
C++使用操作系统内存分配系统(通过
new/delete和malloc/free抽象出来)。如果操作系统使用虚拟内存,你真的无法压缩“堆”。原因是您所拥有的只是虚拟地址,而压缩虚拟内存可能不会像您期望的那样在物理内存中移动数据。 -
如果您对这类内容感兴趣,请阅读jemalloc paper 或mimalloc paper 作为现代高级内存管理的介绍。
-
C/C++ 程序中使用的另一种技术:用于短期、突发分配的内存区域,可以一次性清理。这也可以防止内存碎片。
标签: c++ memory-management