JavaGC学习笔记(一)


1.简介
Java在JVM虚拟机上的垃圾回收(GC)机制,在合适的时间触发垃圾回收,将不需要的内存空间回收释放,避免无限制的内存增长导致的OOM。

1.1 Java堆内存结构
Java将堆内存分为3大部分:年轻代、老年代和永久代。其中年轻代又进一步划分为Eden、S0、S1(Survivor)三个区。
结构如下图所示:

2、清理算法
A. 年轻代:复制算法
B. 老年代:标记-清除算法 & 标记-整理算法
2.1复制算法:
思路就是把把空间分两部分,一块(A0)用完了,把还活着的对象复制到另外一块(A1),再删除(A0),之后的new的对象都放到A1,当A1满的时候,在把A1活着对象复制到A0,删除A1…….一直循环

因为大部分的对象生命都很短。所以年轻代内存空间划分成一块较大的Eden区和两块较小的Survivor区,两块Survivor区域的大小保持一致。
1、新new的对象,放入Eden+S0
2、Eden+S0满了,把活着的对象复制到S1,删除Eden+S0
3、新new的对象,放入Eden+S1
4、循环….
默认Eden和Survivor的大小比例是8:1:1,也就是说新生代中牺牲掉10%的空间而不是一半的空间。

2.2标记-清除算法

 


2.3标记-整理算法

 

3垃圾收集器
3.1收集器介绍
年轻代域: 
1、Serial:默认的年轻代收集器,单线程、复制算法实现,回收时挂起所有线程,造成应用停顿
2、ParNew:多线程、复制算法实现,回收时挂起所有线程,造成应用停顿
3、Parallel Scavenge:多线程、复制算法来进行垃圾回收。收集器关注的是吞吐量,即使得应用能够充分使用CPU。
老年代:
1、Serial Old:默认的老年代收集器,采用单线程和标记-整理算法来实现垃圾回收。
2、Parallel Old:Parallel Scavenge收集器的老年代版本,采用多线程和标记-整理算法来实现老年代的垃圾回收。
3、CMS:收集器是一款真正实现了并发收集的老年代收集器, CMS收集器可以最大程度地减少因垃圾回收而造成应用停顿的时间

配合使用关系如下:

3.2 使用收集器
-XX:+UseSerialGC虚拟机运行在client模式下的默认值,使用这个参数表示虚拟机将使用Serial + Serial Old收集器组合进行垃圾回收。
(-XX:+UseSerialGC表示使用这个设置,而-XX:-UseSerialGC表示禁用这个设置。)
-XX:+UseParNewGC使用这个设置以后,虚拟机将使用ParNew + Serial Old收集器组合进行垃圾回收。
-XX:+UseConcMarkSweepGC使用这个设置以后,虚拟机将使用ParNew + CMS + Serial Old的收集器组合进行垃圾回收。注意Serial Old收集器将作为CMS收集器出现Concurrent Mode Failure失败后的后备收集器来进行回收(将会整理内存碎片)。
-XX:+UseParallelGC虚拟机运行在server模式下的默认值。使用这个设置,虚拟机将使用Parallel Scavenge + Serial Old(PS MarkSweep)的收集器组合进行垃圾回收。
-XX:+UseParallelOldGC使用这个设置以后,虚拟机将使用Parallel Scavengen + Parallel Old的收集器组合进行垃圾回收。


3.3 GC日志格式
<datestamp>:[GC[<collector>:<start occupancy1>-><end occupancy1>(total size1),<pause time1> secs]<start occupancy2>-><end occupancy2>(total size2),<pause time2> secs] [Times:<user time> <system time>, <real time>]

datestamp : 表示GC日志产生的时间点,如果指定的jvm参数是-XX:+PrintGCTimeStamps,那么输出的是相对于虚拟机启动时间的时间戳,如果指定的是-XX:+PrintGCDateStamps,那么输出的是具体的时间格式,可读性更高
GC : 表示发生GC的类型,有GC(代表MinorGC)和FullGC两种情况
collector : 表示GC收集器类型,取值可能是DefNew、ParNew、PSYoungGen、Tenured、ParOldGen、PSPermGen等等
start occupancy1 : 表示发生回收之前占用的内存空间
end occupancy1 : 表示发生回收以后还占用的内存空间
total size1 : 该堆区域所拥有的总内存空间
pause time1 : 发生垃圾收集的时间
start occupancy2 : 表示回收前Java堆内存总占用空间
end occupancy2 : 表示回收后Java堆内存还占用的总空间
total size2 : 表示Java堆内存总空间
pause time2 : 表示整个堆回收消耗时间

3.4 收集器逻辑
3.4.1 CMS收集器
3.4.1.1 CMS逻辑介绍

(1) 初始化标记 (inital mark)
这个阶段仅仅是标记了GC Roots能够直接关联到的对象,速度很快,所以基本上感受不到STW带来的停顿。
(2) 并发标记 (concurrent mark)
并发标记阶段完成的任务是从第一阶段收集到的对象引用开始,遍历所有其他的对象引用,并标记所有需要回收的对象。这个阶段,收集线程与用户线程并发交替执行,不必挂起用户线程,所以并不会造成应用停顿。
(3) 并发预清除 (concurrent-pre-clean)
并发预清除阶段是为了下一个阶段做准备,为的是尽量减少应用停顿的时间。
(4) 重新标记 (remark)
这个阶段将会修正并发标记期间因为用户程序继续运作而导致标记产生变动的那部分对象的标记记录(有可能对象重新被引用或者新对象可以被回收)。这个阶段的停顿时间比初始标记阶段要长一些,但是远比并发标记的时间短。
(5) 并发清除 (concurrent sweep)
这个阶段将真正执行垃圾回收,将那些不被使用的对象内存回收掉。
(6) 并发重置 (concurrent reset)
收集器做一些收尾的工作,以便下一次GC周期能有一个干净的状态。

3.4.1.2 CMS日志分析

1,当cms gc开始;CMS-initial-mark:31745K(32768K),指标记时,old代的已用空间和总空间
2,CMS-concurrent-mark,此阶段是和应用线程并发执行的,所谓并发收集器指的就是这个,主要作用是标记可达的对象。
3,CMS-concurrent-preclean,此阶段主要是进行一些预清理,因为标记和应用线程是并发执行的,因此会有些对象的状态在标记后会改变,此阶段正是解决这个问题因为之后的Rescan阶段也会stop the world,为了使暂停的时间尽可能的小,也需要preclean阶段先做一部分工作以节省时间
4,CMS-concurrent-abortable-preclean阶段,加入此阶段的目的是使cms gc更加可控一些,作用也是执行一些预清理,以减少Rescan阶段造成应用暂停的时间
5,再下一个阶段是第二个stop the world阶段了,即Rescan阶段,此阶段暂停应用线程,对对象进行重新扫描并标记;
YG occupancy:964861K(2403008K),指执行时young代的情况
CMS remark:961330K(1572864K),指执行时old代的情况
此外,还打印出了弱引用处理、类卸载等过程的耗时
6,再下一个阶段是CMS-concurrent-sweep,进行并发的垃圾清理
7,最后是CMS-concurrent-reset,为下一次cms gc重置相关数据结构

3.4.1.3 cms常见错误
Concurrent Mode Failure:一个是在年老代被用完之前不能完成对无引用对象的回收;一个是当新空间分配请求在年老代的剩余空间中得到满足
方法一:是降低触发CMS的阀值-XX:CMSInitiatingOccupancyFraction;
方法二:减少年轻代大小,避免放入年老代时需要分配大的空间。
promotion failed:进行Minor GC时,survivor space放不下、对象只能放入旧生代,而此时旧生代也放不下造成的;

3.4.2 G1
待补充

3.4.3 UseSerialGC

待补充

3.4.4 其他

待补充

4 JVM调优
1、堆大小设置
2、回收器选择
3、辅助信息

4.1 堆内存相关
-Xms用于指定Java应用使用的最小堆内存,如-Xms1024m表示将Java应用最小堆设置为1024M。
-Xmx用于指定Java应用使用的最大堆内存,如-Xmx1024m表示将Java应用最大堆设置为1024m。过小的堆内存可能会造成程序抛出OOM异常,所以正常发布的应用应该明确指定这两个参数。并且,一般会选择将-Xms与-Xmx设置成一样大小,防止JVM动态调整堆内存容量对程序造成性能影响。
-Xmn可以设置堆内存中年轻代的容量,以此达到间接控制老年代容量的作用,因为没有JVM参数可以直接控制老年代的容量。如-Xmn256m表示将年轻代容量设置为256M。假如这个时候额外指定了-Xms1024m -Xmx1024m,那么老年代的容量为768M(1024-256=768)。
-XX:NewRatio=1 可以控制年轻代和老年代的比例
-XX:SurvivorRatio这个参数用于设置新生代中Eden区和Survivor(S0、S1)的容量比值。默认设置为-XX:SurvivorRatio=8表示Eden区与Survivor的容量比例为8:1:1。
4.2 收集器配置
-XX:PretenureSizeThreshold设置直接晋升到老年代的对象大小,大于这个参数的对象将直接在老年代分配,而不是在新生代分配。注意这个值只能设置为字节,如-XX:PretenureSizeThreshold=3145728表示超过3M的对象将直接在老年代分配。
-XX:MaxTenuringThreshold设置晋升到老年代的对象年龄。每个对象在坚持过一次Minor GC之后,年龄就会加1,当超过这个值时就进入老年代。默认设置为-XX:MaxTenuringThreshold=15。
-XX:ParellelGCThreads设置并行GC时进行内存回收的线程数。只有当采用的垃圾回收器是采用多线程模式,包括ParNew、Parallel Scavenge、Parallel Old、CMS,这个参数的设置才会有效。
-XX:CMSInitiatingOccupancyFraction设置CMS收集器在老年代空间被使用多少(百分比)后触发垃圾收集。默认设置-XX:CMSInitiatingOccupancyFraction=68表示老年代空间使用比例达到68%时触发CMS垃圾收集。仅当老年代收集器设置为CMS时候这个参数才有效。
-XX:+UseCMSCompactAtFullCollection设置CMS收集器在完成垃圾收集后是否要进行一次内存碎片整理。仅当老年代收集器设置为CMS时候这个参数才有效。
-XX:CMSFullGCsBeforeCompaction设置CMS收集器在进行多少次垃圾收集后再进行一次内存碎片整理。如设置-XX:CMSFullGCsBeforeCompaction=2表示CMS收集器进行了2次垃圾收集之后,进行一次内存碎片整理。仅当老年代收集器设置为CMS时候这个参数才有效。


4.3 GC日志相关
-XX:+PrintGCDetails表示输出GC的详细情况。
-XX:+PrintGCDateStamps指定输出GC时的时间格式,比指定-XX:+PrintGCTimeStamps可读性更高。
-Xloggc指定gc日志的存放位置。如-Xloggc:/var/log/myapp-gc.log表示将gc日志保存在磁盘/var/log/目录,文件名为myapp-gc.log。

猜你喜欢

转载自www.cnblogs.com/pansZZZ/p/9072204.html