JVM之GC

垃圾回收算法

讲垃圾回收算法之前,先简单说一下两个算法依据

  1. 引用计数算法:

java在运行时,一个对象如果有被引用则对象实例+1,引用失效-1,垃圾回收时,找到引用为0的回收即可,这种算法缺点比较明显,当对象互相引用时,则无法回收到。JVM没有采用该算法
2. 可达性分析算法
相对于引用计数算法,有根节点的概念,通过根节点的对象引用链,来找到不需要回收的对象。最终无法到达的对象即为需要回收的对象。跟节点如何选取:类加载器、Thread、虚拟机栈本地变量、static成员、常量引用、本地方法栈等等都是root节点的选择对象

标记清除

将需要回收的对象进行标记,最后进行清除

特点:效率一般且会产生碎片

标记整理

和标记清除类似,先标记需要回收的对象,不同之处在于清除对象后,会将现有的对象进行整理来解决碎片化的问题。但是比较耗时

复制算法

复制算法会将内存按容量分为两块区域,每次只使用其中一块。回收垃圾时,将保留的对象直接复制到另外一块区域,同时直接清除本区域的对象。

特点:简单高效、空间利用率低

分带垃圾回收

分带垃圾回收是将内存分类,Young区和old区,每个分区使用不同的回收算法。来高效的利用回收算法的优缺点。JVM中也是使用了改逻辑来处理的。
Young区:复制算法
Old区:标记清除或标记整理

垃圾收集器

串行收集器Serial

开启参数:-XX:+UseSerialGC

串行收集器属于一种传统的收集器。内存很小时会使用,比如一些嵌入式的程序中会使用该收集器。

特点是:简单高效,效率高。但是必须暂停其他所有的工作线程

并行收集器Parallel

开启参数:-XX:+UseParallelGC,-XX:+UseParallelOldGC
service模式默认的收集器

并发收集器Concurrent

CMS:-XX:+UseConcMarkSweepGC -XX:+UseParNewGC

G1:-XX:+UseG1GC

JVM常用的收集器和优化点

以JDK8为例,可以查看官网:HotSpot虚拟机垃圾收集优化指南

并行收集器

并行收集器(也称为吞吐量收集器)是相对于串行收集器而言的,区别在于收集垃圾时,使用的多线程来收集。收集时也是需要暂停应用程序的。

设置线程数 -XX:ParallelGCThreads=<N>
核心数N小于8时等于N,大于8时为5/8。 也可以用上诉方式调优

在并行收集器中使用了一种自动调整的方法,JDK推荐使用以下3个参数来帮助收集器来调整性能。 以下排名有先后顺序

  • 最大垃圾回收暂停时间 -XX:MaxGCPauseMillis=<N>
  • 吞吐量 -XX:GCTimeRatio=<N> 比如配置99,则表示收集时间 1/1+N 为1%
  • 内存占用 -Xmx

通过这三个参数,收集器会自动优化程序,达到以上的要求。

Generation Size Adjustment

同时我们还可以调整分区的动态适应参数来帮助其更好的优化

  • -XX:YoungGenerationSizeIncrement=<Y> young generation增长比率 默认为20
  • -XX:TenuredGenerationSizeIncrement=<T> tenured generation增长比率 默认为20
  • -XX:AdaptiveSizeDecrementScaleFactor=<D> 缩小因子,如果增长比率是X,那么缩小比率就是 X / D, 默认为4,也就是5%

如果collector决定在启动的时候就增长generation,那么会在原增长比率上有一个增加量,这个增加量会随着gc次数越来越低,这个主要是为了提高启动的性能。缩小时没有增加量。

如果最大pause time的目标没有达成,那么会一次自会缩小一个generation。如果两个generation都达不到目标,那么pause time较长的那个会先被缩小

如果throughput的目标没有达到,那么两个generation区域都会被增加。然后按照比例扩展,比如young generation的gc时间占到总gc时间的25%,而增长比率是20%,那么实际会增长5%。

CMS

CMS适合在响应时间要求比较的服务器上使用,

G1