Chao's Blog Chao's Blog
首页
  • vue

    • vue路由
  • 学习笔记

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《ES6 教程》
    • 《Vue》
    • 《React》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
    • JS设计模式总结
  • java
  • spring
  • springboot
  • springcloud
  • git
  • maven
  • nginx
  • tomcat
  • springmvc
  • jvm
  • 图数据库
  • mysql数据库
  • redis数据库
  • windows下docker安装nginx并挂载目录
  • linux命令
  • linux安装软件
  • linux脚本
  • idea
  • vscode
  • 归档
  • 综合项目

    • 若依项目
    • mall项目
  • java
  • mybatis
  • xxl-job
  • mybatis
GitHub (opens new window)

~chao

永远菜鸟,不断努力~
首页
  • vue

    • vue路由
  • 学习笔记

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《ES6 教程》
    • 《Vue》
    • 《React》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
    • JS设计模式总结
  • java
  • spring
  • springboot
  • springcloud
  • git
  • maven
  • nginx
  • tomcat
  • springmvc
  • jvm
  • 图数据库
  • mysql数据库
  • redis数据库
  • windows下docker安装nginx并挂载目录
  • linux命令
  • linux安装软件
  • linux脚本
  • idea
  • vscode
  • 归档
  • 综合项目

    • 若依项目
    • mall项目
  • java
  • mybatis
  • xxl-job
  • mybatis
GitHub (opens new window)
  • java

  • spring

  • springboot

  • springcloud

  • git

  • maven

  • nginx

  • tomcat

  • springmvc

  • jvm

    • JVM上篇-内存与垃圾回收篇

    • JVM中篇-字节码与类的加载篇

    • JVM下篇:性能监控与调优篇

    • 个人总结

      • jvm相关
      • JVM常用调优参数方法
    • 正则表达式

    • 消息中间件

    • python

    • 后端
    • jvm
    • 个人总结
    ~chao
    2023-03-29
    目录

    JVM常用调优参数方法

    # JVM常用调优方法

    文章转载自:(46条消息) JVM常用调优方法_jvm常用调优方式_dragon@oo的博客-CSDN博客 (opens new window)

    一、常用调优方法

    1**、将新对象预留在新生代**

    由于 Full GC 的成本要远远高于 Minor GC ,因此尽可能将对象分配在新生代,在JVM 调优中,可以为应用程序分配一个合理的新生代空间,以最大限度避免新对象直接进去老年代。

    注意:由于新生代垃圾回收的速度高于老年代回收,因此,将年轻对象预留在新生代有利于提高整体的 GC 效率

    2**、大对象进入老年代**

    大对象占用空间多,直接放入新生代中会扰乱新生代GC,新生代空间不足将会把大量的较小的年轻代对象移入到老年代中,这对GC来说是相当不利的。如果有短命大对象,对GC来说将会是一场灾难,原本存放于老年代的永久对象,被短命大对象塞满,扰乱了分代内存回收的基本思路,因此,在开发过程中,尽可能避免使用短命的大对象。使用参数 -XX:PretenureSizeThreshold 设置大对象直接进入老年代的阀值,当对象超过这个阀值时,将直接在老年代中分配。其中, -XX:PretenureSizeThreshold 只对串行收集器和新生代并行收集器有效,并行回收收集器不识别这个参数。

    注意:短命的大对象对垃圾回收是一场灾难,目前木有一种特别好的回收方法处理这个问题,因此尽可能避免使用短命的大对象。

    3**、设置对象进入老年代的年龄**

    在堆中每个对象都有自己的年龄,如果对象在 eden 区,经过一次 GC 后还存活,则被移动到 survivor 区中,对象年龄加 1,以后每经过一次 GC 依然存活的,对象年龄就加 1。当对象年龄达到阀值时,就移动到老年代,这个阀值用以下参数设置:

    -XX:MaxTenuringThreshold:默认值是15,这个参数是指定进入老年代的最大年龄值,对象实际进入老年代的年龄是 JVM 在运行时根据内存使用情况动态计算的。

    如果希望对象尽可能长地留在新生代中,可以设置一个较大的阀值。

    4**、稳定与震荡的堆大小**

    稳定的堆大小对垃圾回收是有利的,获得一个稳定堆大小的方法就是设置 -Xmx 和 -Xms 一样的值。不稳定的堆也不是木有用处,让堆大小在一个区间内震荡,在系统不需要使用大内存时压缩堆空间,使 GC 应对一个较小的堆,可以加快单次 GC 的速度。基于这种思想,JVM 提供了两个参数用于压缩和扩展堆空间,参数如下:

    -XX**:MinHeapFreeRatio**:设置堆空间最小空闲比例,默认是 40 ,当堆空间的空闲比例小于这个值时,JVM 便会扩展堆空间

    -XX**:MaxHeapFreeRatio**:设置堆空间的最大空闲比例,默认是 70,当堆空间的空闲比例大于这个值时,JVM 便会压缩堆空间,得到一个较小的堆

    注意:当 -Xms 和 -Xmx 相等时,-XX:MinHeapFreeRatio 和 -XX:MaxHeapFreeRatio 这两个参数无效

    5**、吞吐量优先设置**

    机器配置是 4G 内存 和 32 核 CPU,配置参数如下:

    -Xms3800m -Xmx3800m**(堆的初始值和最大值一样)**

    -Xmn2g**(新生代大小)**

    -Xss128k**(线程栈大小,减少它使剩余的系统内存支持更多的线程)**

    -XX**:+UseParallelGC****(新生代使用并行回收收集器)**

    -XX**:ParallelGCThreads=20****(垃圾回收的线程数)**

    -XX**:+UseParallelOldGC** (老年代使用并行回收收集器)

    6**、使用大页案例**

    使用大的内存分页可以增强 CPU 的内存寻址能力,从而提高系统的性能,参数设置如下:

    -XX**:LargePageSizeInBytes**:设置大页的大小

    7**、降低停顿案例**

    为了降低应用软件在垃圾回收时的停顿,首先考虑的使用关注系统停顿的 CMS 回收器,为了减少 Full GC 的次数,应尽可能将对象预留在新生代,新生代 Minor GC 的成本远远小于老年代的 Full GC

    -Xms3800m -Xmx3800m**(堆的初始值和最大值一样)**

    -Xmn2g**(新生代大小)**

    -Xss128k**(线程栈大小,减少它使剩余的系统内存支持更多的线程)**

    -XX**:ParallelGCThreads=20****(垃圾回收的线程数)**

    -XX**:+UseConcMarkSweepGC****(老年代使用 CMS 收集器)**

    -XX**:+UseParNewGC****(新生代使用并行收集器)**

    -XX**:SurvivorRatio=8****(设置 eden : survivor = 8 : 1)**

    -XX**:TargetSurvivorRatio****(设置 survivor 的使用率为 90%,默认是50%,提高了survivor 区的使用率,当存放的对象超过这个数值,则对象会向老年代压缩)**

    -XX**:MaxTenuringThreshold=31****(设置年轻对象晋升到老年代的最大年龄是31,默认是15,设为31是尽可能地将对象留在新生代)**

    二、常用JVM参数

    1**、JIT编译参数**

    JVM 的 JIT(Just-In-Time)编译器,可以在运行时将字节码编译成本地代码,从而提高函数的执行效率。参数设置如下

    -XX**:CompileThreshold**:JIT 编译的阀值,当函数的调用超过这个值时,JIT 就将字节码编译成本地机器码。在 client 模式下,取值是 1500,在 server 模式下,取值是 10000

    2**、堆快照(堆 Dump)**

    在性能问题排查中,分析堆快照(Dump)是必不可少的一环。获取程序的堆快照文件有多种方法,下面介绍一种常用的方法,即使用 -XX:+HeapDumpOnOutOfMemoryError 参数在程序发生 OOM 时,导出应用程序的当前堆快照。这是一种非常有效的方法,因为当程序发生 OOM 退出系统时,一些瞬时信息都随着程序的终止而消失,而重现 OOM 问题往往比较困难或者耗时,因此当发生 OOM 时,将堆信息保存到文件中是至关重要的,通过下面的参数设置:

    -XX**:+HeapDumpOnOutOfMemoryError(开启堆快照)**

    -XX**:HeapDumpPath=C:/m.hprof(保存文件到哪个目录)**

    导出的 Dump 文件可以通过 Visual VM 等多种工具查看分析,进而定位问题,如下图所示:

    3**、错误处理**

    系统发生 OOM 错误时,JVM 在错误发生时运行一段第三方脚本,重置系统,设置参数如下:

    -XX**:OnOutOfMemoryError=C:\reset.bat**

    4**、获取 GC 信息**

    获取 GC 信息是 java 应用程序调优最重要的一环,下面介绍一些常用的设置参数:

    -XX**:+PrintGC(-verbose:gc):**输出打印简要的 GC 信息,包括 GC 前的堆栈情况和 GC 后的堆栈大小和堆栈的总大小

    -XX**:+PrintGCDetails:**输出打印详细的 GC 信息,不仅包括基本信息,还给出了新生代、老年代和永久区各自的 GC 信息

    -XX**:+PrintGCTimeStamps:**额外输出 GC 发生的时间,可以推断出 GC 的频率和间隔

    -XX**:+PrintTenuringDistribution -XX:MaxTenuringThreshold=18:**查看新生代晋升老年代的实际阀值(-XX:+PrintTenuringDistribution),设置的最大年龄为18( -XX:MaxTenuringThreshold=18)

    -XX**:+PrintHeapAtGC:**每次 GC 时都会打印堆的详细使用情况,输出量很巨大。它分为两个部分:GC 前的堆信息和 GC 后的堆信息,这里包含了新生代、老年代和永久区的使用大小和使用率,还包括了新生代中 eden 区和 survivor 区的使用情况

    -XX**:+PrintGCApplicationStoppedTime:**应用程序在 GC 发生时的停顿时间

    -XX**:+PrintGCApplicationConcurrentTime:**应用程序在 GC 停顿期间的执行时间

    -Xloggc**:C:/gc.log:**将 GC 日志信息输出到具体位置的文件中,便于日后日志分析

    注意:详细的 GC 信息是进行 JVM 调优的重要参考信息,可以根据 GC 日志,设置合理的堆大小及相关垃圾回收器的参数

    5**、类和对象跟踪**

    JVM 提供了一组参数,用于获取系统运行时加载、卸载类的信息,参数设置如下:

    -XX**:TraceClassLoading**:跟踪类加载情况

    -XX**:TraceClassUnloading**:跟踪类的卸载情况

    -verbose**:class**:相当于同时设置 -XX:TraceClassLoading 和 -XX:TraceClassUnloading 两个参数

    -XX**:+PrintClassHistogram**:打印运行时实例的信息,当设置此参数后,使用 Ctrl + Break 会输出系统内类的统计信息,从左到右依次显示了序号、实例数量、总大小和类名等信息

    6**、控制GC**

    -XX**:DisableExplicitGC**:禁止 GC 操作,即禁止在程序中使用 System.gc() 触发 Full GC

    -Xnoclassgc:禁止类的回收

    -Xingc**:**增量式的 GC ,增量式的 GC 使用特定的算法让 GC 线程和应用程序线程交叉执行,从而减少应用程序因 GC 产生的停顿时间

    -Xverify**:none**:关闭类校验器

    -XX**:+UseLargePages****:启用大页,使用大页后,内存分页的表项就会减少,从而提升CPU从虚拟内存地址映射到物理内存地址的能力**

    -XX**:LargePageSizeInBytes****:指定大页的大小**

    # 三、触发gc的条件和解决方案

    1、System.gc()方法的调用

    system.gc(), 此方法的调用是建议JVM进行Full GC,虽然只是建议而非一定,但很多情况下它会触发 Full GC,从而增加Full GC的频率,也即增加了间歇性停顿的次数。

    解决方案:强烈建议能不使用此方法就别使用,让虚拟机自己去管理它的内存,可通过通过**-XX:+ DisableExplicitGC**来禁止RMI调用System.gc。

    2、老年代代空间(old/Tenured)不足

    老年代空间只有在新生代对象转入及创建为大对象、大数组时才会出现不足的现象,当执行Full GC后空间仍然不足,则抛出如下错误:java.lang.OutOfMemoryError: Java heap space 为避免以上两种状况引起的Full GC

    解决方案:调优时应尽量做到让对象在Minor GC阶段被回收、让对象在新生代多存活一段时间及不要创建过大的对象及数组

    3、永久区(perm)或者元数据区(matespace)空间不足(jdk<=7 ,在jdk8里面是metaspace)

    JVM规范中运行时数据区域中的方法区,在HotSpot虚拟机中又被习惯称为永生代或者永生区,Permanet Generation中存放的为一些class的信息、常量、静态变量等数据,当系统中要加载的类、反射的类和调用的方法较多时,Permanet Generation可能会被占满,在未配置为采用CMS GC的情况下也会执行Full GC。如果经过Full GC仍然回收不了,那么JVM会抛出如下错误信息:java.lang.OutOfMemoryError: PermGen space

    解决方案:为避免Perm Gen占满造成Full GC现象,可采用的方法为增大Perm Gen空间或转为使用CMS GC

    4、CMS GC时出现promotion failed和concurrent mode failure

    对于采用CMS进行老年代GC的程序而言,尤其要注意GC日志中是否有promotion failed和concurrent mode failure两种状况,当这两种状况出现时可能会触发Full GC。promotion failed是在进行Minor GC时,survivor space放不下、对象只能放入老年代,而此时老年代也放不下造成的;concurrent mode failure是在执行CMS GC的过程中同时有对象要放入老年代,而此时老年代空间不足造成的(有时候“空间不足”是CMS GC时当前的浮动垃圾过多导致暂时性的空间不足触发Full GC)。

    解决方案:增大survivor space、老年代空间或调低触发并发GC的比率(-XX:CMSInitiatingOccupancyFraction=70,预留空间为70%),但在JDK 5.0+、6.0+的版本中有可能会由于JDK的bug29导致CMS在remark完毕后很久才触发sweeping动作。对于这种状况,可通过设置-XX: CMSMaxAbortablePrecleanTime=5(单位为ms)来避免。

    5、统计得到的Minor GC晋升到旧生代(Eden到S2和S1到S2的和)的平均大小大于老年代的剩余空间

    这是一个较为复杂的触发情况,Hotspot为了避免由于新生代对象晋升到旧生代导致旧生代空间不足的现象,在进行Minor GC时,做了一个判断,如果之前统计所得到的Minor GC晋升到旧生代的平均大小大于旧生代的剩余空间,那么就直接触发Full GC。例如程序第一次触发Minor GC后,有6MB的对象晋升到旧生代,那么当下一次Minor GC发生时,首先检查旧生代的剩余空间是否大于6MB,如果小于6MB,则执行Full GC。当新生代采用PS GC时,方式稍有不同,PS GC是在Minor GC后也会检查,例如上面的例子中第一次Minor GC后,PS GC会检查此时旧生代的剩余空间是否大于6MB,如小于,则触发对旧生代的回收。除了以上4种状况外,对于使用RMI来进行RPC或管理的Sun JDK应用而言,默认情况下会一小时执行一次Full GC。

    解决方案:通过在启动时通过**- java -Dsun.rmi.dgc.client.gcInterval=3600000来设置Full GC执行的间隔时间或通过-XX:+ DisableExplicitGC**来禁止RMI调用System.gc。

    6、堆中分配很大的对象

    所谓大对象,是指需要大量连续内存空间的java对象,例如很长的数组,此种对象会直接进入老年代,而老年代虽然有很大的剩余空间,但是无法找到足够大的连续空间来分配给当前对象,此种情况就会触发JVM进行Full GC。

    解决方案:为了解决这个问题,CMS垃圾收集器提供了一个可配置的参数,即**-XX:+UseCMSCompactAtFullCollection**开关参数,用于在“享受”完Full GC服务之后额外免费赠送一个碎片整理的过程,空间碎片问题没有了,但停顿时间不得不变长了,JVM设计者们还提供了另外一个参数 -XX:CMSFullGCsBeforeCompaction,这个参数用于设置在执行多少次不压缩的Full GC后,跟着来一次带压缩的

    编辑 (opens new window)
    上次更新: 2024/01/26, 05:03:22
    jvm相关
    正则表达式字符表

    ← jvm相关 正则表达式字符表→

    最近更新
    01
    python使用生成器读取大文件-500g
    09-24
    02
    Windows环境下 Docker Desktop 安装 Nginx
    04-10
    03
    使用nginx部署多个前端项目(三种方式)
    04-10
    更多文章>
    Theme by Vdoing | Copyright © 2022-2024 chaos | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式