调优领域:
- 内存
- 锁竞争
- CPU占用
- IO
- GC
确定目标:
低延迟/高吞吐量?选择合适的GC
- 并发收集器: CMS G1 ZGC
- 并行收集器: Parallel GC
- Zing
七大垃圾收集器:
1、串行GC:Serial收集器(1:1)
串行收集器是最古老的,最稳定,效率高的收集器,只使用一个线程去回收但其进行垃圾回收过程中可能会产生较长的停顿。虽然在收集垃圾的过程中需要暂停其他的工作线程,但是简单高效,对于单CPU环境来说,没有线程交互的开销可以获得最高的单线程垃圾收集效率。
2、并行GC:ParNew(N:1)
使用多线程进行垃圾回收,在垃圾回收时,会暂停所有其他工作线程,直到GC结束。
ParNew时Serial收集器新生代的并行多线程版本,最常见的应用场景是配合老年代CMS GC工作,其余行为和Seria收集器完全一样,ParNew垃圾收集器在垃圾收集过程中同样要暂停所有其他的工作线程。它是很多JVM运行在Server模式下新生代的默认垃圾收集器。
3、并行回收:Parallel Scavenge(N:N)
Parallel Scavenge收集器类似ParNew,也是一个新生代垃圾收集器,使用复制算法,也是一个并行的多线程的垃圾收集器,俗称吞吐量优先收集器。相当于是串行收集器在新生代和老年代的并行化。
自适应调节策略也是Parallel Scavenge收集器与ParNew收集器的一个重要区别。
它重点关注可控制吞吐量,高吞吐量意味着高效利用CPU时间,它多用于在后台运算而不需要太多交互的任务。
【吞吐量 = 用户代码运行时间/(用户代码运行时间+垃圾回收时间)】
使用Parallel Scavenge收集器。开启参数后,新生代用复制算法,老年代用复制标记整理算法。
4、Parallel Old收集器
Parallel Old收集器是Parallel Scavenge收集器的老年代版本,使用多线程的标记整理算法,在JDK1.6开始提供。
5、并发标记清除GC(CMS)
CMS收集器是一个以获取最短回收停顿时间为目标的收集器。适合应用在互联网站或BS系统的服务器上,因为这类场景重视服务器的响应速度,希望系统的停顿时间尽可能短。CMS适合堆内存大、CPU核数多的服务器端应用,也是G1出现之前大型应用的首选收集器。
CMS的优势是并发收集停顿少,并发是指与用户线程一起执行。
开启收集器的JVM参数:-XX:+UseConcMarkSweepGC 开启后会自动开启 -XX:+UseParNewGC
6、Serial Old收集器
Serial Old收集器是Serial垃圾收集器老年代版本,同样是单线程的收集器,使用标记整理算法。
主要运行在Client默认的JVM老年代垃圾回收器。
在Server模式下,主要有两个用途:
- 在JDK1.5之前与新生代Parallel Scavenge收集器搭配使用。(Parallel Scavenge+Serial Old)
- 作为老年代版中使用CMS收集器的后备垃圾回收方案。
7、G1
G1是一款面向服务端应用的收集器,应用在多CPU和大容量内存的环境中,在实现高吞吐量的同时,尽可能减少GC回收的时间(STW的时间)它和CMS一样,可以和应用线程并发执行。并且具有以下特性:
- 整理空闲空间的速度更快
- 需要更多的时间来预测GC停顿时间
- 不希望牺牲大量的吞吐性能
- 不需要更大的Java堆内存
G1的收集目的是取代CMS收集器,与CMS相比它有一个整理内存的过程,所以不会产生大量的内存碎片。而且G1的STW是可控的,G1在停顿时间上加了预测机制,用户可以指定期望的停顿时间。
G1可以重复利用多CPU、多核环境硬件优势来减少STW。整体上采用标记整理算法,局部采用复制算法,不会产生内存碎片。
最快的GC是不发生GC
首先排除减少因为自身编写的代码而引发的内存问题
- 查看Full GC前后的内存占用,考虑以下几个问题
- 数据是不是太多?
- 数据表示是否太臃肿
- 对象图
- 对象大小
- 是否存在内存泄漏
新生代调优
- 新生代的特点
- 所有的new操作分配内存都是非常廉价的
- TLAB
- 死亡对象回收零代价
- 大部分对象用过即死(朝生夕死)
- MInor GC 所用时间远小于Full GC
- 所有的new操作分配内存都是非常廉价的
面试题:新生代内存越大越好么?
答:不是,
- 新生代内存太小:频繁触发Minor GC,会STW,会使得吞吐量下降。
- 新生代内存太大:老年代内存占比有所降低,会更频繁地触发Full GC。而且触发Minor GC时,清理新生代所花费的时间会更长。
- 新生代内存设置为内容纳【并发量(请求-响应)*】的数据为宜。
幸存区调优
- 幸存区需要能够保存 当前活跃对象+需要晋升的对象。
- 晋升阈值配置得当,让长时间存活的对象尽快晋升。