JVM专题-垃圾回收
Posted IT-老牛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JVM专题-垃圾回收相关的知识,希望对你有一定的参考价值。
文章目录
1.垃圾回收器分类
相关概念:
- 并行收集:指多条垃圾收集线程并行工作,但此时用户线程仍处于等待状态
- 并发收集:指用户线程与垃圾收集线程同时工作(不一定是并行的可能会交替执行)。用户程序在继续运行,而垃圾收集程序运行在另一个CPU上
- 吞吐量:即CPU用于运行用户代码的时间与CPU总消耗时间的比值(吞吐量 = 运行用户代码时间 / ( 运行用户代码时间 + 垃圾收集时间 )),也就是。例如:虚拟机共运行100分钟,垃圾收集器花掉1分钟,那么吞吐量就是99%
串行
- 底层是一个单线程的垃圾回收器
- 适合堆内存较小,cpu核数较少,适合个人电脑
吞吐量优先
- 多线程
- 适合堆内存较大的场景
- 需要多核cpu支持(否则多线程争强一个cpu效率低)
- 让单位时间内,STW的时间最短 0.2 + 0.2 = 0.4
响应时间优先
- 多线程
- 适合堆内存较大
- 需要多核cpu
- 尽可能让单次STW的时间最短 0.1 + 0.1 + 0.1 + 0.1 + 0.1 = 0.5
1.1.串行
# 虚拟机参数
-XX:+UseSerialGC=Serial+SerialOld
串行垃圾回收器分为两个部分,分开运行的。新生代空间不足了触发Serial
完成MinorGC
,老年代空间不足了触发SerialOld
完成FullGC
安全点:让其他线程都在这个点停下来,以免垃圾回收时移动对象地址,使得其他线程找不到被移动的对象。
阻塞:因为是串行的,所以只有一个垃圾回收线程。且在该线程执行回收工作时,其他线程进入阻塞状态
Serial 收集器:
- 定义:Serial收集器是最基本的、发展历史最悠久的收集器
- 特点:单线程收集器。采用复制算法。工作在新生代
Serial Old收集器:
- 定义:Serial Old是Serial收集器的老年代版本
- 特点:单线程收集器。采用标记-整理算法。工作在老年代
1.2.吞吐量优先
parallel并行,指的是,多个垃圾回收器可以并行的运行,占用不同的cpu。但是在此期间,用户线程是被暂停的,只有垃圾回收线程在运行。
# 虚拟机参数
# 并行
-XX:+UseParallelGC ~ -XX:+UseParallelOldGC
-XX:+UseAdaptiveSizePolicy
-XX:GCTimeRatio=ratio
-XX:MaxGCPauseMillis=ms
-XX:ParallelGCThreads=n
parallel并行,指的是,多个垃圾回收器可以并行的运行,占用不同的cpu。但是在此期间,用户线程是被暂停的,只有垃圾回收线程在运行。
Parallel 收集器:
定义:与吞吐量关系密切,故也称为吞吐量优先收集器
特点:并行的,工作于新生代,采用复制算法
Parallel Old 收集器:
定义:是Parallel 收集器的老年代版本
特点:并行的,工作与老年代,采用标记-整理算法
1.3.响应时间优先
# 虚拟机参数
# 并发
-XX:+UseConcMarkSweepGC~ -XX:+UseParNewGC~SerialOld
-XX:ParallelGCThreads=n~ -XX:ConcGCTreads=threads
-XX:CMSInitiatingOccupancyFraction=percent
-XX:+CMSScavengeBeforeRemark
- Concurrent 并发、MarkSweep标记清除。基于标记清除且支持并发的一个垃圾回收器
- 并发意味着垃圾回收时,其他的用户线程也可以并发运行,与垃圾回收线程抢占cpu
- CMS在垃圾回收的某些阶段是不需要STW,进一步减少需要STW的时间
UseConcMarkSweepGC
是工作在老年代的垃圾回收器,与之对应的是UseParNewGC
,工作在新生代的垃圾回收器,基于复制算法。- CMS回收器有时候会发生并行失败的情况,这时候CMS回收器会退化成SerialOld的单线程的基于标记整理的垃圾回收器。
CMS老年代回收过程
- 当老年代空间不足时,所有进程运行到安全点暂停,然后垃圾回收的线程进行初始标记,初始标记比较快,只是标记根对象。此过程会
Stop The World
,阻塞其他用户线程。 - 之后达到下一个安全点,其他用户线程也可以继续运行了,此时垃圾回收线程进行并发标记,即可以跟其他用户线程并发工作,然后讲垃圾标记出来。此过程不会STW
- 达到下一个安全点后,进行重新标记,因为上一个并发标记时,其他用户线程也在并发执行,所有可能会产生新对象新引用,对垃圾回收线程造成了干扰,需要重新标记。此过程会STW
- 到下一个安全点后,其他用户进程恢复,垃圾回收线程开始并发地清理垃圾,恢复运行。
细节
- 垃圾回收的并发数受参数影响。
-XX:ParallelGCThreads=n
表示并行的垃圾回收线程数,一般跟cpu数目相等-XX:ConcGCTreads=threads
并发的垃圾回收线程数目,一般是ParallelGCThreads
的1/4
。即一个cpu
做垃圾回收,剩下3个cpu留给人家用户线程。
- CMS垃圾回收器对cpu的占用率并不高,但是用户线程不能完全占用cpu,吞吐量变小了。
- CMS在执行最后一步并发清理的时候,由于其他线程还在运行,就会产生新的垃圾,而新的垃圾只有等到下次垃圾回收才能清理了。这些垃圾被称为浮动垃圾,所以要预留一些空间来存放浮动垃圾。
-XX:CMSInitiatingOccupancyFraction=percent
,开始执行CMS
垃圾回收时的内存占比,早期默认65
,即只要老年代内存占用率达到65%的时候就要开始清理,留下35%的空间给新产生的浮动垃圾。-XX:+CMSScavengeBeforeRemark
。在重新标记阶段,有可能新生代的对象会引用老年代的对象,重新标记时需要扫描整个堆,做可达性分析时,只要新生代的引用存在,不管有没有必要,都会通过新生代引用找到老年代,但是这其实对性能影响有些大。因为新生代对象很多,且很多要作为垃圾被回收。可达性分析又会通过新生代引用去找老年代,但是就算找到了老年代,这些新生代还是要被回收,也就是说,本来没有必要查找老年代。所以在重新标记之前,把新生代先回收了,就不会存在新生代引用老年代,然后去查找老年代了。- 新生代的回收是通过
-XX:+UseParNewGC
,垃圾回收之后,新生代对象少了,自然重新标记的压力就轻了。 - 因为
CMS
基于标记清除,有可能会产生比较多的内存碎片。这样的话,会造成将来给对象分配空间时,空间不足时,如果minorGC
后内存空间也不足。那么由于标记清除,老年代的空间也不足,造成并发失败。于是CMS
退化成SerialOld
串行地垃圾回收,通过标记整理,来得到空间。但是这样会导致垃圾回收的时间变得很长(要整理),结果本来是响应时间优先的回收器,响应时间长,给用户造成不好的体验。
以上是关于JVM专题-垃圾回收的主要内容,如果未能解决你的问题,请参考以下文章