NUMA就是非统一内存访问架构(英语:non-uniform memory access,简称NUMA),是一种为多处理器的电脑设计的内存架构,内存访问时间取决于内存相对于处理器的位置。在NUMA下,处理器访问它自己的本地内存的速度比非本地内存(内存位于另一个处理器,或者是处理器之间共享的内存)快一些。如下图所示,Node0中的CPU如果访问Node0中的内存,那就是访问本地内存,如果它访问了Node1中的内存,那就是远程访问,性能较差:
非统一内存访问架构的特点是:
被共享的内存物理上是分布式的,所有这些内存的集合就是全局地址空间。所以处理器访问这些内存的时间是不一样的,显然访问本地内存的速度要比访问全局共享内存或远程访问外地内存要快些。另外,NUMA中内存可能是分层的:本地内存,群内共享内存,全局共享内存。
JEP345希望通过实现NUMA-aware的内存分配,改进G1在大型机上的性能。
现代的multi-socket服务器越来越多都有NUMA,意思是,内存到每个socket的距离是不相等的,内存到不同的socket之间的访问是有性能差异的,这个距离越长,延迟就会越大,性能就会越差!
G1的堆组织为固定大小区域的集合。一个区域通常是一组物理页面,尽管使用大页面(通过 -XX:+UseLargePages)时,多个区域可能组成一个物理页面。
如果指定了+XX:+UseNUMA选项,则在初始化JVM时,区域将平均分布在可用NUMA节点的总数上。
在开始时固定每个区域的NUMA节点有些不灵活,但是可以通过以下增强来缓解。为了为mutator线程分配新的对象,G1可能需要分配一个新的区域。它将通过从NUMA节点中优先选择一个与当前线程绑定的空闲区域来执行此操作,以便将对象保留在新生代的同一NUMA节点上。如果在为变量分配区域的过程中,同一NUMA节点上没有空闲区域,则G1将触发垃圾回收。要评估的另一种想法是,从距离最近的NUMA节点开始,按距离顺序在其他NUMA节点中搜索自由区域。
该特性不会尝试将对象保留在老年代的同一NUMA节点上。
JEP 345专门用于实现G1垃圾收集器的NUMA支持,仅用于内存管理(内存分配),并且仅在Linux下。对于NUMA体系结构的这种支持是否也适用于其他垃圾回收器或其他部分(例如任务队列窃取),尚不清楚。
由于维护和兼容性测试的成本,在JDK8时将Serial+CMS,ParNew+Serial Old这两个组合声明为废弃(JEP173),并在JDK9中完全取消了这些组合的支持(JEP214)
ParallelScavenge+SerialOld GC 的GC组合要被标记为Deprecate了
这个GC组合需要大量的代码维护工作,并且这个GC组合很少被使用,因为它的使用场景应该是一个很大的Young区和一个很小的Old区,这样的话,Old区用SerialOld GC去收集停顿时间才可以勉强被接受。
;废弃了Parallelyoung generationGC 与SerialOldGC组合 (-XX:+UseParallelGC 与 -XX:-UseParallelOldGC 配合开启),现在使用-XX:+UseParallelGC -XX:-UseParallelOldGC或者使用 -XX:-UseParallelOldGC会出现如下警告
自从G1出现后,CMS在JDK9中就被标记为Deprecate了
当CMS停止工作时,会把 Serial Old GC作为备选方案,而它是JVM中性能最差的垃圾收集方式,停顿几秒甚至十秒都有可能。
移除了CMS垃圾收集器,如果继续在JDK14中使用-XX:+UseConcMarkSweepGC 不会报错,仅仅给出一个warning警告
warning: Ignoring option UseConcMarkSweepGC; support was removed in 14.0
G1回收器hotSpot已经默认使用有几年了,我们还看到两个新的GC JAVA11中的ZGC和openJDK12中的Shenandoah,后两者主要特点是:低停顿时间
Shenandoah非Oracle官方发布的,是OpenJDK于JAVA12发布的
收集器名称 | 运行时间 | 总停顿时间 | 最大停顿时间 | 平均停顿时间 |
---|---|---|---|---|
Shenandoah | 387.602s | 320ms | 89.79ms | 53.01ms |
G1 | 312.052s | 11.7s | 1.24s | 450.12ms |
CMS | 286.264s | 12.78s | 4.39s | 852.26ms |
ParallelScavenge | 260.092s | 6.59s | 3.04s | 823.75ms |
JAVA14之前,ZGC仅仅支持Linux
基于一些开发部署和测试的需要,ZGC在JDK14中支持在macOS 和windows,因此许多桌面级应用可以从ZGC中受益,目前还是一个实验性版本,要想在macOS 和windows上使用。
ZGC与Shenandoah目标非常相似,都是在尽量减少吞吐量的情况下,实现对任意堆大小(TB级)都可以把垃圾收集器停顿时间限制在10毫秒以内的低延迟时间。
ZGC 收集器是一款基于Region内存布局的,暂时不设分代的,使用了读屏障,染色指针和内存多重映射等技术来实现并发的标记压缩算法,以低延迟为首要目标的一款垃圾收集器。现在想在macOS 和windows上使用ZGC, 方式如下
-XX:+UnlockExperimentalVMOptions -XX:+UseZGC
关于ZGC的一些测试数据
ZGC目前还处于一个实验状态,但是性能非常亮眼,未来将在服务端大内存、低延迟应用上作为首选的垃圾收集器。