Memory management 为什么不为主存使用日志结构分配器

Memory management 为什么不为主存使用日志结构分配器,memory-management,filesystems,dynamic-memory-allocation,allocator,Memory Management,Filesystems,Dynamic Memory Allocation,Allocator,我刚刚学习了日志结构的文件系统。我很困惑,为什么不使用日志结构作为主内存分配器呢。它可以显著减少碎片。日志结构的文件系统使用对循环日志的顺序写入来持久化文件系统数据,并且通常以非常相同的方式处理更新。在某种程度上,日志结构的文件系统必须回收未使用的空间(日志中的过时条目),以使其可用于将来的写入。在一个简单的实现中,只要文件系统磁盘空间用完,就可以通过重新写入日志并跳过进程中未使用的条目来回收未使用的条目 本机代码的内存分配器也可以做类似的事情。一个简单的实现需要一大块内存和下一个指针,在分配过

我刚刚学习了日志结构的文件系统。我很困惑,为什么不使用日志结构作为主内存分配器呢。它可以显著减少碎片。

日志结构的文件系统使用对循环日志的顺序写入来持久化文件系统数据,并且通常以非常相同的方式处理更新。在某种程度上,日志结构的文件系统必须回收未使用的空间(日志中的过时条目),以使其可用于将来的写入。在一个简单的实现中,只要文件系统磁盘空间用完,就可以通过重新写入日志并跳过进程中未使用的条目来回收未使用的条目

本机代码的内存分配器也可以做类似的事情。一个简单的实现需要一大块内存和下一个指针,在分配过程中需要增加这些指针。解除分配需要将条目标记为已释放(可以是条目中的标志或专用的空闲列表),或者解除分配需要以其他方式进行限制(以先进先出的顺序解除分配,只能解除分配整个分配空间)。 事实上,这种分配器被称为“线性分配器”,并在今天使用。一个优点是分配性能,另一个优点是,如果以FIFO顺序进行释放或影响整个分配空间,则释放操作简单高效。堆栈分配是一个突出的例子。JVM通常使用线性分配器进行对象分配。ApacheWebServer使用其变体来处理每个请求的内存分配

由于空间回收的困难,将线性分配器用作通用分配器的问题更大。要回收空间,将条目标记为自由项是不够的,因为这可能导致高度碎片化,并破坏线性分配的优势(只需为实际分配任务增加一个指针)。因此,与文件系统类似,必须压缩分配空间,使其仅包含分配的条目,并且可用空间可用于线性分配。压缩需要移动分配的条目—这是一个更改和使其以前已知的地址无效的过程。在本机代码中,分配器不知道对已分配项(存储为指针的地址)的引用位置。必须对现有引用进行修补,以使分配器操作对调用方透明,这对于像
malloc
这样的通用分配器是不可行的

为什么不可行?更新现有引用需要以下步骤:

  • 挂起所有线程以停止所有分配条目变量(除非使用了所谓的“写屏障”)
  • 扫描寄存器、堆栈和堆以查找指向移动对象的指针
    • 指针的确切位置未知,与引用匹配的数据可能会被误认为引用(例如,对于像Boehm这样不执行复制的保守GC来说,这不是问题。误报只会延迟收集),因此内存可能会损坏
    • 指针可能未对齐,因此扫描必须在指针大小的窗口按字节前进的情况下进行
    • 由于诸如指针标记之类的策略以及诸如XOR链表之类的数据结构,指针可能会被混淆
    • 代码可能依赖于前面的指针值(与托管代码不同,可以读取引用的值)
  • 恢复所有以前挂起的线程
使用RTTI,可以提供所需的metdata,但是将指针传递到您无法控制的库(例如glibc)仍然是一个问题。因此,在有限的范围内,这是可以实现的。通用分配器必须在所有本机代码场景中都可用-对于需要移动分配项的线性分配器,有太多的约束使其不可行。除此之外,用于停止线程和建立写屏障的低级机制可能会干扰分配器用户使用的类似机制(例如JVM)

但是,对于托管代码,这是常见的做法。例如,复制垃圾收集器维护两个分配空间(从空间和到空间),以处理压缩。在垃圾回收期间,仅将引用的分配项复制到其他分配空间。完成后,可以再次以线性方式处理分配

在特定的场景中,已经使用了使用日志结构文件系统策略的分配器。对于针对本机代码的通用内存分配,移动分配项是不可行的,这意味着线性分配器无法取代更传统的内存分配策略


一种替代方法是使用池分配器,它为固定大小的分配条目提供分配空间,而不是采用线性分配路线来减少碎片。通过这样限制分配空间,可以减少碎片。许多通用分配器使用池分配器进行小型分配。在某些情况下,这些应用程序空间以每个线程为单位存在,以消除锁定的需要并提高CPU缓存利用率。

非常感谢您的回复。我也想知道:1。后台线程复制垃圾回收会影响线性分配器运行时性能吗?2.正如您所提到的,移动分配条目对于本机代码是不可行的。它是指非托管内存语言,如C/C++。为什么不可行呢?3.哪些特定场景更喜欢日志结构内存分配器。它是否更关注内存利用率而不是性能?(我认为要求索引查找每个访问的移动分配条目会影响性能)@tuffy chow I an