垃圾回收算法手册读书笔记(三) 内存分配

内存分配

基本内存分配策略:

  • 顺序分配
  • 空闲链表分配

顺序分配

对于一个可分配的空闲内存块,顺序分配将从内存块的其中一端开始进行分配。 顺序分配

顺序分配主要特征如下:

  • 简单:所需数据结构非常简单,只需要一个空闲指针(free pointer)和一个界限指针(limit pointer)。分配过程中只需要不断的移动空闲指针
  • 高效:相较于空闲链表分配,顺序分配可以给赋值器带来更好的空间局部性
  • 回收器限制:不适用于非移动式回收器

空闲链表分配

空闲链表分配使用某种数据结构来记录空闲内存单元的位置与大小,该数据结构即是空闲内存单元集合。空闲内存单元的组织形式并不一定是链表,不过我们这里仍使用”空闲链表”这个名字来称呼这种记录内存单元的数据结构。

空闲链表分配时,分配器通过空闲链表查找并选择一个内存单元并从中进行分配,如果该内存单元的空间大于所需分配的空间,剩余空间将会返还空闲链表。 其算法实现通常是顺序遍历内存单元进行查找选择,这种方法称为顺序适应分配,典型的顺序适应包括:

  • 首次适应
  • 循环首次适应
  • 最佳适应

首次适应分配

顺序遍历空闲内存单元,选择第一个满足条件的内存单元。然而这样会导致较小的空闲内存单元会在空闲链表头部聚集,从而导致分配速度变慢

循环首次适应分配

首次适应分配的一个变种,不同点在于每次分配查找不是从空闲链表头部开始,而是从上一次成功分配的位置开始。该算法可以避免较小的空闲内存单元在头部聚集。

最佳适应分配

在空闲链表中找到满足分配要求且空间最小的空闲内存单元。其目的在于减少内存碎片的产生。但是查找需要遍历整空闲链表,性能较差(尽管通过使用其他数据结构能够降低查找过程的时间复杂度,但相比其他两种算法仍有额外的开销)

内存碎片化

随着内存不断的分配与释放,大块的可用内存不断的被拆分成大量小块的可用内存。内存的碎片化至少带来两种负面影响:

  • 导致内存分配的失败,即所有可用内存块的大小均不满足分配要求
  • 导致应用消耗更多的地址空间,常驻内存页以及高速缓存行 唯一解决内存碎片化问题的方案就是使用整理式或者复制式回收

并发系统中的内存分配

多线程环境下,分配过程的许多操作都需要原子化以确保分配数据结构不被破坏。原子化操作往往需要使用原子操作或者锁,这样一来内存分配就可能成为性能瓶颈

最基本的解决方案就是为每个线程开辟独立的内存分配空间,当独立的内存空间耗尽,再向全局内存空间申请新的内存块,这样一来只有与全局内存空间交互时才需要原子化。