JVM 垃圾回收器 ZGC内存管理
学习ZGC,主要通过学习ZGC设计与实现书籍,并以博客的形式记录学习内容
ZGC 实现了两级内存管理:虚拟内存和物理内存,并且实现了物理内存和虚拟内存的映射关系。这和操作系统中虚拟地址和物理地址设计思路基本一致。
多视图映射
操作系统支持多个虚拟地址同时映射到一个物理地址上,当我们操作其中一个虚拟地址,所有虚拟地址都能访问到最新的数据。 Linux主要通过系统函数mmap完成视图映射,多个视图映射就是多次调用mmap函数,多次调用的返回结果就是不同的虚拟地址。 ZGC仅支持Linux 64位系统,所以ZGC是通过系统调用mmap来完成地址多视图映射的。
页面设计
ZGC将内存划成小的分区,在ZGC中称为页。ZGC支持3种页面,分别为小页面、中页面和大页面。其中小页面指的是2MB的页面空间,中页面指的32MB的页面空间,大页面指受操作系统控制的大页。 在ZGC中,不同对象的大小会使用不同的页面类型。上表中,MinObjectAlignmentInBytes 的默认值是8,它是由参数ObjectAlignmentInBytes控制,大小在8~256之间,且为2的幂次。通常来说,粒度越大,处理器访问内存的速度越快,但可能导致过多的浪费。在实际中可以根据应用系统对象的平均大小来合理地设置该值。 小页面优先回收;中页面和大页面尽量不回收。
对NUMA的支持
统一内存访问(UMA),指的是任何CPU访问任何内存的速度是一致的,不必考虑不同内存地址之间的差异。各个处理器与内存单元通过互联总线进行连接,各个CPU之间没有主从关系。
非统一内存访问(NUMA),在多CPU下,为了提升性能,将CPU和内存集成在一个单元上,CPU访问本地存储器的速度比访问非本地存储器快一些。
ZGC是支持NUMA的,在进行小页面分配时会优先从本地内存分配,当不能分配时才会从远端的内存分配。对于中页面和大页面的分配,ZGC并没有要求从本地内存分配,而是直接交给操作系统,由操作系统找到一块能满足ZGC页面空间。
小页面支持NUMA,中页面和大页面不支持NUMA。
ZGC中的物理内存管理
ZGC中内存空间的分配是以页面为粒度(最小粒度是2MB)。ZGC为了减少对操作系统物理内存频繁操作,设计了自己的物理内存管理系统,ZGC中物理内存实际上仅仅记录了操作系统物理内存的使用情况。 ZGC中物理内存管理的基本单位是段,它包含start和end。在内存分配阶段每一段是2MB,也就是说ZGC在向操作系统请求物理内存的最小粒度是2MB,超过2MB的内存空间会被划分成多个段。 假如应用程序申请一个超大的对象需要10MB空间,则将其转化成5个段,每个段为2MB。在ZGC和操作系统交互时,将分成5次向操作系统申请内存,所以可以把一个大对象分配在操作系统层面不连续的物理空间中。但是在ZGC的物理内存管理中,分配成功后会把这些段进行合并,因为这5个段是连续的地址。 段是ZGC向操作系统请求内存的基本单位,而页面是对象内存管理的的单位。
ZGC中的虚拟内存管理
对于小页面ZGC会从虚拟内存的头部开始分配,对于中页面和大页面ZGC从虚拟空间的尾部开始分配。这样设计的目的是方便对象的管理,小页面分配和释放的成本都不高,但是分配和释放中页面和大页面成本很高。
对象空间分配
页面分配
在对象空间分配时,如果页面还有空间,则能快速的分配对象,如果页面空间不足,则需要申请新的页面,页面分配主要通过页面管理器实现。
|