jvm调优总结

rushoooooo rushoooooo     2022-12-31     291

关键词:

 

写在之前的话

最近在工作中总是遇到服务的QPS在压测的时间比较低的情况。于是就开始了性能优化之旅,这个过程是很是曲折。一开始的时候认为是服务的业务逻辑比较多,大部分的时间都花在优化业务逻辑,减少与其他服务和数据库等接口的调用,使用缓存等方式提高性能。上述的工作都是对性能有提升的,但是对于一个熟练的农民工而言,对语言的特性已经成竹在胸,很难通过优化一两句代码获得质的提升。由于目前都是采用微服务的开发方式,JVM的参数是自己设置的,就想着在这个方面去优化一下。

通过在压测过程中检测(使用jstat工具)gc的次数及时间来分析,这个服务在压力测试中的gc次数已经到了影响提升性能的关键因素。于是便着手减少gc的次数。

本次优化的目的有两个

1、将转移到老年代的对象数量降低到最小;

2、减少full GC的执行时间;

从网上看了一些JVM调优的方法,其中一位仁兄分享的程序调优方法觉得跟自己的情况特别服务,特别的在这里跟大家分享下:

一切都是为了这一步,调优,在调优之前,我们需要记住下面的原则:

1、多数的Java应用不需要在服务器上进行GC优化;

2、多数导致GC问题的Java应用,都不是因为我们参数设置错误,而是代码问题;

3、在应用上线之前,先考虑将机器的JVM参数设置到最优(最适合);

4、减少创建对象的数量;

5、减少使用全局变量和大对象;

6GC优化是到最后不得已才采用的手段;

7、在实际使用中,分析GC情况优化代码比优化GC参数要多得多;

为了达到上面的目的,一般地,你需要做的事情有:

1、减少使用全局变量和大对象;

2、调整新生代的大小到最合适;

3、设置老年代的大小为最合适;

4、选择合适的GC收集器;

JVM堆栈组成及划分

有了上面的思路,下面我们一起来了解下JVM堆栈的结构。JVM堆栈由三部分组成:新生代、老年代和永久代。下图形象的描述了各个区的划分:

技术分享图片

从图中我们可以看出堆内存空间的结构

1. JVM堆内存由三大区组成:新生代(Yong Generation)、老年代(Tenured Generation)和永久带(Perm Generation);

2. 新生代由三部分组成:一个Eden区、两个Survivor区;

3. 两个Survivor区一个叫From,一个叫To,从字面叫法上可以看出两个的作用;

4. Eden和Survivor默认比例是8:1。一般情况下,新创建的对象都会被分配到Eden区(一些大对象特殊处理),这些对象经过第一次Minor GC后,如果仍然存活,将会被移到Survivor区。对象在Survivor区中每熬过一次Minor GC,年龄就会增加1岁,当它的年龄增加到一定程度时,就会被移动到年老代中。

GC过程中对象的移动过程

在GC开始的时候,对象只会存在于Eden区和名为“From”的Survivor区,Survivor区“To”是空的。紧接着进行GC,Eden区中所有存活的对象都会被复制到“To”,而在“From”区中,仍存活的对象会根据他们的年龄值来决定去向。年龄达到一定值(年龄阈值,可以通过-XX:MaxTenuringThreshold来设置)的对象会被移动到年老代中,没有达到阈值的对象会被复制到“To”区域。经过这次GC后,Eden区和From区已经被清空。这个时候,“From”和“To”会交换他们的角色,也就是新的“To”就是上次GC前的“From”,新的“From”就是上次GC前的“To”。不管怎样,都会保证名为To的Survivor区域是空的。Minor GC会一直重复这样的过程,直到“To”区被填满,“To”区被填满之后,会将所有对象移动到年老代中。

技术分享图片

JVM运行时关键参数设置

参数名称

说明

Tip

-Xms

堆的最小值

32位系统 下,一般限制在1.5G~2G;64为操作系统对内存无限制

-Xmx

堆空间的最大值

32位系统 下,一般限制在1.5G~2G;64为操作系统对内存无限制

-Xmn

年轻代大小

整个堆大小=年轻代大小 + 年老代大小 + 持久代大小 。持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。

-Xss

设置每个线程的堆栈大小

JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。更具应用的线程所需内存大小进行调整。在相同物理内 存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。

-Xms

堆的最小值

32位系统 下,一般限制在1.5G~2G;64为操作系统对内存无限制

有关年轻代的JVM参数

1) -XX:NewSize和-XX:MaxNewSize

用于设置年轻代的大小,建议设为整个堆大小的1/3或者1/4,两个值设为一样大。

2) -XX:SurvivorRatio

用于设置Eden和其中一个Survivor的比值,这个值也比较重要。设置年轻代中Eden区与Survivor区的大小比值。设置为4,则两个Survivor区与一个Eden区的比值为2:4,一个Survivor区占整个年轻代的1/6

3) -XX:NewRatio=4

设置年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)。设置为4,则年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5

4) -XX:+PrintTenuringDistribution

这个参数用于显示每次Minor GC时Survivor区中各个年龄段的对象的大小。

5) -XX:MaxPermSize=16m

建议设置持久代大小为16m。

6) -XX:InitialTenuringThreshol和-XX:MaxTenuringThreshold

用于设置晋升到老年代的对象年龄的最小值和最大值,每个对象在坚持过一次Minor GC之后,年龄就加1。

-XX:MaxTenuringThreshold=0。设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概论。

吞吐量收集器

1) -XX:+UseSerialGC

激活串行垃圾收集器 例如单线程面向吞吐量的垃圾收集器 推荐用于只有单个CPU的JVM

2) -XX:+UseParallelGC

使用多线程并行执行年轻代垃圾收集

3) -XX:+UseParallelOldG

除了激活年轻代并行垃圾收集,也激活了年老代并行垃圾收集

4) -XX:ParallelGCThreads

-XX:ParallelGCThreads=<value> 指定并行垃圾收集的线程数量

5) -XX:-UseAdaptiveSizePolicy

垃圾收集器能将堆大小动态变动像GC设置一样应用到不同的堆区域,只要有证据表明这些变动将能提高GC性能

6) -XX:GCTimeRatio

-XX:GCTimeRatio=<value>指定JVM吞吐量要达到的目标值
指定目标应用程序线程的执行时间和总的程序执行时间达到N/(N+1)的目标比值
通过-XX:GCTimeRatio=9我们要求应用程序线程在整个执行时间中至少9/10是活动的(因此,GC线程占用其余1/10)
-XX:GCTimeRatio的默认值是99,也就是说,应用程序线程应该运行至少99%的总执行时间

7) -XX:MaxGCPauseMillis

通过-XX:GCTimeRatio=<value>告诉JVM最大暂停时间目标值[ms为单位]

CMS收集器

1) -XX:+UseConcMarkSweepGC

激活CMS收集器 JVM默认使用的是并行处理器

2) -XX:UseParNewGC

使用CMS收集器时 激活年轻代使用多线程并行执行垃圾回收
注意:
最新的JVM版本,当使用-XX:+UseConcMarkSweepGC时,-XX:UseParNewGC会自动开启。
因此,如果年轻代的并行GC不想开启,可以通过设置-XX:-UseParNewGC来关掉。

3) -XX:+CMSConcurrentMTEnabled

并发的CMS阶段以多线程执行 默认开启

4) -XX:ConcGCThreads

-XX:ConcGCThreads=<value>定义并发CMS中运行的线程数
如果还标志未设置,JVM会根据并行收集器中的-XX:ParallelGCThreads参数的值来计算出默认的并行CMS线程数。该公式是ConcGCThreads = (ParallelGCThreads + 3)/4。因此,对于CMS收集器
-XX:ParallelGCThreads标志不仅影响“stop-the-world”垃圾收集阶段,还影响并发阶段。

5) -XX:CMSInitiatingOccupancyFraction

-XX:CMSInitiatingOccupancyFraction=来设置,该值代表老年代堆空间的使用率。比如,value=75意味着第一次CMS垃圾收集会在老年代被占用75%时被触发。通常CMSInitiatingOccupancyFraction的默认值为68(之前很长时间的经历来决定的)。

6) -XX:+UseCMSInitiatingOccupancyOnly

命令JVM不基于运行时收集的数据来启动CMS垃圾收集周期
JVM通过CMSInitiatingOccupancyFraction的值进行每一次CMS收集,而不仅仅是第一次

7) -XX:+CMSClassUnloadingEnabled

CMS默认不会对永久代进行垃圾回收 如果希望对永久代进行垃圾回收 可以设置此标志
注意,即使没有设置这个标志,一旦永久代耗尽空间也会尝试进行垃圾回收,但是收集不会是并行的,而再一次进行Full GC。

8) -XX:+CMSIncrementalMode

开启CMS收集器的增量模式
ps:增量模式会经常暂停CMS过程 以便对应用程序作出完全的让步

9) -XX:+ExplicitGCInvokesConcurrent和-XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses

1.-XX:+ExplicitGCInvokesConcurrent
命令JVM无论什么时候调用系统GC,都执行CMS GC,而不是Full GC
2.-XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses
保证当有系统GC调用时,永久代也被包括进CMS垃圾回收的范围内。因此,通过使用这些标志,我们可以防止出现意料之外的”stop-the-world”的系统GC。

10) -XX:+DisableExplicitGC

该标志将告诉JVM完全忽略系统的GC调用(不管使用的收集器是什么类型)

总结

JVM参数是死的,你的服务所对应的场景才是活的。在调优的过程中需要根据自己的业务需要不断的调整参数、测试、再调整的迭代方式直到性能达到最优。

推荐大家使用jstat这款Java自动的检测GC的工具,对于查看系统的GC信息有很大的帮助。

参考资料

官方提供的JVM参数一览表:

http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html

https://blog.csdn.net/rodesad/article/details/51544977

「jvm」调优参数总结

参考技术A因此我们一般设置-Xms、-Xmx这两个参数相等,可以避免在每次GC后动态调整堆的大小带来的影响。吞吐量和停顿时间是互斥的。对于后端服务(比如后台计算任务),吞吐量优先考虑(并行垃圾回收);对于前端应用,RT响应... 查看详情

jvm参数调优详解(代码片段)

文章目录JVM调优什么是JVM调优?为什么要JVM调优?总结JVM参数调优JVM参数类型JVM常见参数JVM调优建议年轻代大小选择老年代大小选择较小堆引起的碎片问题JVM调优实战VM堆内存调优调整最大堆内存和最小堆内存调整新生代... 查看详情

jvm参数调优详解(代码片段)

文章目录JVM调优什么是JVM调优?为什么要JVM调优?总结JVM参数调优JVM参数类型JVM常见参数JVM调优建议年轻代大小选择老年代大小选择较小堆引起的碎片问题JVM调优实战VM堆内存调优调整最大堆内存和最小堆内存调整新生代... 查看详情

jvm调优总结-垃圾回收面临的问题

如何区分垃圾   上面说到的“引用计数”法,通过统计控制生成对象和删除对象时的引用数来判断。垃圾回收程序收集计数为0的对象即可。但是这种方法无法解决循环引用。所以,后来实现的垃圾判断算法中,... 查看详情

jvm监控和调优常用命令工具总结(代码片段)

JVM监控和调优在Java应用和服务出现莫名的卡顿、CPU飙升等问题时总是要分析一下对应进程的JVM状态以定位问题和解决问题并作出相应的优化,在这过程中Java自带的一些状态监控命令和图形化工具就非常方便了。本文总结了最常... 查看详情

jvm调优总结

 写在之前的话最近在工作中总是遇到服务的QPS在压测的时间比较低的情况。于是就开始了性能优化之旅,这个过程是很是曲折。一开始的时候认为是服务的业务逻辑比较多,大部分的时间都花在优化业务逻辑,减少与其他服... 查看详情

jvm调优—内存区域

一、jvm内存区域关于jvm内存模型的具体总结,这篇博客有详细的总结:​​​jvm内存区域​​我们主要关注jvm中最主要的三块内存—堆,栈,方法区,而最容易最经常出现的内存错误OutOfMemoryError就很经常的很频繁的出现在这三... 查看详情

jvm-常用内存调优参数总结

一、内存调整参数-Xmx2g  设置堆内存最大值为2g-Xmx512m 设置堆内存最大值为512m-Xms1g  设置堆内存最小值1g-Xmn 设置堆新生代的大小,例如:-Xmn512m-XX:PermSize  设置PermGeneration的最小值,例如:-XX:PermSize=32... 查看详情

jvm调优总结-xms-xmx-xmn-xss

堆大小设置JVM中最大堆大小有三方面限制:相关操作系统的数据模型(32-bt还是64-bit)限制;系统的可用虚拟内存限制;系统的可用物理内存限制。32位系统下,一般限制在1.5G~2G;64为操作系统对内存无限制。我在WindowsServer2003系... 查看详情

jvm系列jvm调优

作者:半身风雪上一节:JVM中常见的垃圾回收器JVM调优前言一、堆空间如何设置二、扩容新生代能提高GC效率吗?三、JVM是如何避免MinorGC时扫描全堆的?四、常量池4.1、Class常量池(静态常量池)4.2、运行时常量4.3、字符串常量... 查看详情

tomcat调优总结(tomcat自身优化linux内核优化jvm优化)(代码片段)

Tomcat自身的调优是针对conf/server.xml中的几个参数的调优设置。首先是对这几个参数的含义要有深刻而清楚的理解。以tomcat8.5为例,讲解参数。同时也得认识到一点,tomcat调优也受制于linux内核。linux内核对tcp连接也有几个参数可... 查看详情

jvm性能调优

JVM性能调优JVM垃圾回收与性能调优总结JVM调优的几种策略 650)this.width=650;"src="http://dl2.iteye.com/upload/attachment/0101/2383/3d11dfb9-18ca-32f6-8e45-48522c670e92.jpeg"title="点击查看原始大小图片"class="magplus"width="700"hei 查看详情

java系列文章(全)

...器与系统类加载器深入理解JVM—JVM内存模型JVM-堆与栈JVM调优总结-基本垃圾回收算法JVM调优总结-垃圾回收面临的问题JVM调优总结-分代垃 查看详情

2021秋招最新java面试题|jvm剖析与常用的调优总结(代码片段)

...基础篇面试题文章目录JAVA基础篇面试题1.什么是GCRoots2.JVM调优和参数配置3.常用的JVM调优参数4.分析GC日志5.四种引用强引用软引用弱引用虚引用6.常见的JVM异常/错误1.什么是GCRootsGCRoots是一组活跃的引用;常用于判断对象是否... 查看详情

jvm性能调优

JVM垃圾回收与性能调优总结JVM调优的几种策略  一、JVM内存模型及垃圾收集算法 1.根据Java虚拟机规范,JVM将内存划分为:New(年轻代)Tenured(年老代)永久代(Perm) 其中New和Tenured属于堆内存,堆内存会从JVM启动... 查看详情

写得太好了!树莓派安装docker

二、六大性能调优技术(JVM调优+网络调优+数据库调优+LINUX内核调优+中间件底层探索+容器环境调优)手绘板(脑图)1、JVM调优JVM调优必备理论知识-GcCOLLECTOR-三色标记垃圾回收算法串讲JVM常见参数... 查看详情

写得太好了!树莓派安装docker

二、六大性能调优技术(JVM调优+网络调优+数据库调优+LINUX内核调优+中间件底层探索+容器环境调优)手绘板(脑图)1、JVM调优JVM调优必备理论知识-GcCOLLECTOR-三色标记垃圾回收算法串讲JVM常见参数... 查看详情

jvm参数配置及详解-xms-xmx-xmn-xss调优总结

堆大小设置JVM中最大堆大小有三方面限制:相关操作系统的数据模型(32-bt还是64-bit)限制;系统的可用虚拟内存限制;系统的可用物理内存限制.32位系统下,一般限制在1.5G~2G;64为操作系统对内存无限制.我在WindowsServer2003系统,3.5G物理内... 查看详情