我一直在阅读零暂停垃圾收集器的托管语言。据我了解,不停止世界停顿最困难的事情之一就是堆压缩。似乎只有极少数的收集者(例如Azul C4,ZGC)正在或至少正在这样做。
因此,大多数GC都引入了可怕的世界停顿协议(protocol),从而使堆变得紧凑(不好!)。不这样做似乎非常困难,并且确实会降低性能/吞吐量。因此,无论哪种方式,此步骤似乎都是有问题的。
但是,据我所知,大多数(如果不是全部)GC仍偶尔会压缩堆。我还没有看到默认情况下不会执行此操作的现代GC。这使我相信:它必须非常非常重要。如果不是这样,那么肯定会不值得这样做。
同时,我从未见过有人用C++进行内存碎片整理。我确定某个地方的人会这样做,但是-如果我错了,请纠正我-这似乎并不是一个普遍的问题。
我当然可以想象静态内存会有所减轻,但是可以肯定的是,大多数代码库都会进行大量的动态分配?
所以我很好奇,为什么呢?
我的假设(在托管语言中非常重要;在C++中很少这样做)是否正确?如果是,我是否缺少任何解释?

最佳答案

垃圾回收可以压缩堆,因为它知道所有指针的位置。毕竟,它只是完成了对它们的追踪。这意味着它可以移动对象,并将指针(引用)调整到新位置。
但是,C++无法做到这一点,因为它不知道所有指针在哪里。如果内存分配库四处移动,则可能有指向旧位置的悬空指针。
哦,对于长时间运行的进程,C++确实会遭受内存碎片的困扰。这在32位系统上更成问题,因为它可能无法从OS分配内存,因为它可能已经用完了所有可用的1 MB内存块。在64位环境中,几乎不可能创建这么多的内存映射,从而无处可放新的内存映射。但是,如果最后在每个4K内存页中分配了16个字节的内存,那会浪费很多空间。
C和C++应用程序通过使用存储池解决了这一问题。例如,对于Web服务器,它将使用新请求启动池。在该Web请求结束时,池中的所有内容都将被销毁。该池构成了一个不错的,大小恒定的RAM块,可不断重复使用而不会产生碎片。
垃圾回收也倾向于使用回收池,因为它避免了运行大型GC跟踪并在连接结束时回收的麻烦。
在处理虚拟内存之前,某些早期的操作系统(如Apple OS 9)使用的一种方法是处理。分配返回一个句柄,而不是内存指针。该句柄是指向内存中真实对象的指针。当操作系统需要压缩内存或将其交换到磁盘时,它将更改句柄。
我实际上已经在C++中实现了一个类似的系统,使用了一系列处理到共享内存映射psuedo-database中的句柄。压缩 map 后,将扫描句柄表以查找受影响的条目并进行更新。

关于c++ - 内存碎片整理/堆压缩-在托管语言中很常见,但在C++中却不常见。为什么?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/64349058/

10-12 07:34