jvm调优、垃圾回收器相关知识汇总

进行jvm调优的目的就是为了降低full gc的频次和每次full gc的时间,从而提高吞吐率(处理请求的时间/(处理请求的时间+垃圾回收的处理时间))或者缩短响应时间。

1.虚拟机参数

-Xmx   //最大堆空间
-Xms   //初始堆空间大小;如果初始堆空间耗尽,jvm会对堆空间扩容,其扩展上限为最大堆空间。通常-Xms与-Xmx设置为同样大小,避免扩容造成性能损耗
-Xmn   //新生代大小,一般设置为整个堆空间的1/3或者1/4
-XX:SurvivorRatio  //设置新生代中eden空间和from/to空间的比例关系。即-XX:SurvivorRatio=eden/from=eden/to

//例如: -Xmx20m -Xms20m -Xmn1m -XX:SurvivorRation=2   新生代大小为512kb(eden)+256kb(from)+256(to)=1MB,总可用新生代为512kb(eden)+256kb(from或者to)=768kb。(新生成的对象会分配在eden区,如果eden区占满会触发minor gc,将不可回收的对象放入from或to,并且年龄+1)

-XX:NewRation   //设置新生代和老年待的比例。  -XX:NewRatio=老年代/新生代  例如:-Xmx20m -Xms20m --XX:NewRatio=2 新生代大小为20MB*1/3=6mb,老年代为13mb左右

//设置时应尽可能将对象预留在新生代,减少老年代GC的次数(FullGC)

-XX:MaxTenuringThreshold  //设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过survivor区,直接进入年老代。对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在survivor区进行多次复制,可以增加对象在年轻代的存活时间,增加在年轻代即被回收的概率。
-XX:PretenureSizeThreshold  //另大于这个设置值的对象直接在老年代分配,避免在eden区及两个survivor区之间发生大量的内存复制。pretenureSizeThreshold参数只对serial和parnew两款收集器有效,parallel scavenge收集器一般并不需要设置。如果遇到必须使用此参数的场合,可以考虑ParNew加CMS的收集器组合。

-XX:+HeapDumpOnOutOfMemoryError   //当发生内存溢出时导出堆信息
-XX:+HeapDumpPath  //当发生内存溢出时导出堆信息指定输出的存放路径。 -XX:+HeapDumpPath=/opt/OOM.dump
-XX:OnOutOfMemoryError   //当发生内存溢出时可以执行指定脚本   如:-XX:OnOutOfMemoryError=$JAVA_HOME/bin/Printstack

参考博客:https://www.cnblogs.com/hanlinhu/p/9487049.html

2.典型垃圾回收器

  • Serial/Serial Old收集器是最基本最古老的收集器,它是一个单线程收集器,并且在它进行垃圾收集时,必须暂停所有用户线程。Serial收集器是针对新生代的收集器,采用的是Copying算法,Serial Old收集器是针对老年代的收集器,采用的是Mark-Compact算法。它的优点是实现简单高效,但是缺点是会给用户带来停顿。
  • ParNew:ParNew收集器是Serial收集器的多线程版本,使用多个线程进行垃圾收集。
  • Parallel Scavenge收集器是一个新生代的多线程收集器(并行收集器),它在回收期间不需要暂停其他用户线程,其采用的是Copying算法,该收集器与前两个收集器有所不同,它主要是为了达到一个可控的吞吐量。
  • Parallel Old是Parallel Scavenge收集器的老年代版本(并行收集器),使用多线程和Mark-Compact算法。
  • CMS(Current Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器,它是一种并发收集器,采用的是Mark-Sweep算法。
  • G1收集器是当今收集器技术发展最前沿的成果,它是一款面向服务端应用的收集器,它能充分利用多CPU、多核环境。因此它是一款并行与并发收集器,并且它能建立可预测的停顿时间模型。

说明:

-XX:+UseParallelGC
指 定在 New Generation 使用 parallel collector, 并行收集 , 暂停 app threads, 同时启动多个垃圾回收 thread, 不能和 CMS gc 一起使用 . 系统吨吐量优先 , 但是会有较长长时间的 app pause, 后台系统任务可以使用此 gc。UseParallelGC是jdk1.7选择parallel 回收器默认开启的。
-XX:+UseParNewGC
指定在 New Generation 使用 parallel collector, 是 UseParallelGC 的 gc 的升级版本 , 有更好的性能或者优点 , 可以和 CMS gc 一起使用。UseParNewGC需要用户自己手动开启。

参考博文:https://blog.csdn.net/besokuse233/article/details/100915072、https://blog.csdn.net/lxlmycsdnfree/article/details/81531363?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2~default~CTRLIST~default-1.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~CTRLIST~default-1.no_search_link

parallel scavenge与parnew区别:parallel scavenge同样是一个使用复制算法的并行的多线程新生代收集器,但是它的关注点与其他收集器不同,CMS等收集器的关注点是尽可能地缩短垃圾收集时用户线程的停顿时间,而Parallel Scavenge收集器的目标则是达到一个可控制的吞吐量(Throughput)。

停顿时间越短就越适合需要与用户交互的程序,良好的响应速度能提升用户体验,而高吞吐量则可以高效率地利用CPU时间,尽快完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务

Parallel Scavenge收集器提供了两个参数用于精确控制吞吐量,分别是控制最大垃圾收集停顿时间的-XX:MaxGCPauseMillis参数以及直接设置吞吐量大小的-XX:GCTimeRatio参数。

G1回收器的优势和不足

与其他GC收集器相比,G1使用了全新的分区算法。G1在回收期间,可以有多个GC线程同时工作,有效利用多核计算能力。此时用户线程STW(并行)。 G1拥有与应用程序交替执行的能力,部分工作可以和应用程序同时执行,因此,一般来说,不会在整个回收阶段发生完全阻塞应用程序的情况(并发)。

从分代上看,G1依然属于分代型垃圾回收器,它会区分年轻代和老年代,年轻代依然有Eden区和Survivor区。但从堆的结构上看,它不要求整个Eden区、年轻代或者老年代都是连续的,也不再坚持固定大小和固定数量。

相较于CMS,G1还不具备全方位、压倒性优势。比如在用户程序运行过程中,G1无论是为了垃圾收集产生的内存占用(Footprint)还是程序运行时的额外执行负载(Overload)都要比CMS要高。从经验上来说,在小内存应用上CMS的表现大概率有优先与G1,而G1在大内存应用上则发挥其优势。平衡点在6-8GB之间。

参考博文:https://www.jianshu.com/p/8832fd7e2289

3.调优策略

对于JVM的垃圾回收器影响因素较多,例如:IO、临时变量、常驻对象、对象大小、CPU等各种软硬件配置,需要满足的场景也存在差异,例如:吞吐量量优先、响应耗时优先,

  • 如果程序中较多的是“临时变量”的话,可以通过设置适当的年轻代大小,是多数垃圾对象在minor gc时进行回收
  • 设置合理的from/to区大小,避免临时对象(如果一批对象大于了from区的50%)直接进入老年代
  • 年轻代设置过大的话,进行minor gc耗时就会增加。

推荐博文:JVM垃圾收集器选择策略-https://blog.csdn.net/weixin_43230063/article/details/86582050

JVM调优之垃圾回收器选择-https://www.cnblogs.com/dengq/p/13687713.html

4.调优工具arthas

jps工具:查看当前系统中有哪些java进程。

jmap:查看堆内存占用情况。 jmap -heap 进程id (只能检测某个时间点)

jconsole工具:图形界面的、多功能的监测工具,可以连续监测

jvisualvm:升级版的jConsole。

举例:先jps查看进程id ,再jmap -heap 进程id查看堆内存情况。cmd中输入jconsole出现图形界面的

arthas阿尔萨斯的使用

  1. 下载arthas-boot.jar,并通过java -jar arthas-boot.jar启动

  2. 在控制台输入编号,选择要绑定的具体java程序,进入交互模式

  3. 常用的主要命令:

    dashboard  仪表盘
    thread  查看当前线程, 如:  thread -b 查看当前阻塞其他线程的线程
    jvm  查看当前jvm信息
    sc 查看JVM已加载的类信息 ,“Search-Class” 的简写,这个命令能搜索出所有已经加载到 JVM 中的 Class 信息
    sm 查看已加载类的方法信息,“Search-Method” 的简写,这个命令能搜索出所有已经加载了 Class 信息的方法信息
    jad 反编译class文件,如:  jad java.lang.String
    monitor 监控方法执行情况,如: monitor -c 5 demo.MathGame primeFactors,统计该方法5个周期没的执行状况
    watch方法执行数据观测,如: watch demo.MathGame primeFactors "{params,returnObj}"-x 2,-x代表遍历深度
    trace  方法内部调用路径,并输出方法路径上的每个节点上耗时,如: trace demo.MathGame run '#cost > 10',展示耗时大于4ms的调用路径
    stack 输出当前方法被调用的调用路径,如: stack demo.MathGame primeFactors
    tt  TimeTunnel,时空隧道,法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测.使用 -p参数可以重新模拟请求
    watch/stack/trace这个三个命令都支持#cost
    

    参考博文:https://blog.csdn.net/li646495946/article/details/106970270/?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-0.no_search_link&spm=1001.2101.3001.4242.0

    https://blog.csdn.net/hhj13978064496/article/details/110876005

    https://www.jianshu.com/p/def57f3df566

上一篇:JVM面试与调优(15)-G1收集器及收集器使用小结


下一篇:G1收集器的适用场景