jvm调优 详细 多个案例分析

本文详细介绍了何时需要进行JVM调优,包括CPU占用过高、Full GC频繁、内存泄漏等问题的判断。通过分析工具如jstat、jmap、MAT等,配合GC日志和堆转储文件,定位问题原因,如用户线程死循环、内存分配不当等,并给出了调优策略,包括调整对象晋升策略、设置合适的垃圾收集器、优化对象创建速度等。
摘要由CSDN通过智能技术生成

什么时候需要调优

  • 非计算密集型任务cpu占用过高
  • 老年代已使用空间大于70%
  • Full GC频繁
  • 单次GC时间大于1秒
  • 出现OOM
  • 程序的响应速度明显变慢

情况

  • 非计算密集型任务cpu占用过高:有用户线程cpu过高、gc线程cpu过高。用户线程cpu过高一般是出现了死循环,需要查看线程堆栈、结合arthas的watch命令等找出问题根源。gc线程过高一般是Full GC频繁,Full GC频繁一般是因为老年代或方法区(元空间)内存不足。需要对gc日志分析、对堆转储文件分析,确定是哪些对象实例占用了过多内存、反射的类是否过多、被多个类加载器加载的类是否过多等,决定是增加内存大小还是对源码进行处理等。
  • 老年代已使用空间大于70%:有可能发生了内存泄漏、有可能是设置的堆大小无法满足正常业务的需求。需要对堆转储文件分析,确定是哪些对象实例占用了过多内存,并检查是否发生了内存泄漏。对堆大小无法满足正常业务的需求,应调大堆大小,通过-Xms和-Xmx来设置。
  • Full GC频繁:Full GC频繁一般是因为老年代或方法区(元空间)内存不足。需要对gc日志分析、对堆转储文件分析,确定是哪些对象实例占用了过多内存、反射的类是否过多、被多个类加载器加载的类是否过多等,决定是增加内存大小还是对源码进行处理等。
  • 单次GC时间大于1秒
  1. 老年代内存过大。老年代中累积了大量对象时才触发full gc,这次gc的任务很重,耗费的时间很长。通过测试,选择一个合适的老年代大小。
  2. 年轻代过小。年轻代过小,当年轻代空间不足时对象就会分配到老年代,而这些对象可能是“短命”的,但会停留在老年代很久。当full gc时,gc的任务会很重。因此,可以增大年轻代的大小。通过增大-XX:MaxTenuringThreshold=n来设置对象的晋升到老年代的年龄门槛,减缓对象进入老年代。
  3. 创建对象的速度过快。对创建对象过快的代码进行优化,防止短时间内大量创建对象,以致年轻代空间不足而提前进入老年代。
  4. gc线程数过少。gc线程数过少,无法充分利用多核cpu的并行处理。gc日志中 user、sys、real时间需要关注。若real时间 与 (user时间/gc线程数+sys)相差不远,则gc线程数合适。
  5. 进程被swap出内存。当物理内存不足时,系统会将一些内存存于磁盘的swap区,而swap区的访问速度慢很多。检查进程是否被放到swap区了,若是,应该增大物理内存,减少其他进程对内存的占用。
  6. 合适的垃圾收集器。若非jvm专家,建议使用G1。通过-XX:MaxGCPauseMillis来设置最大停顿时间。
  • 出现OOM:老年代或方法区(元空间)内存不足。开启-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=<path>。利用mat(memory analizer tool)对堆转储文件进行分析,确定是哪些对象实例占用了过多内存、反射的类是否过多、被多个类加载器加载的类是否过多等,决定是增加内存大小还是对源码进行处理等。
  • 程序的响应速度明显变慢:检查是否存在上面的四种情况或可能出现了死锁。

调优工具

  • jps:可查看java进程的id、主类名、启动参数等。
  • jstat:可查看堆的情况、gc的统计数据等。

例如
jstat -gc 1000 10 # 每隔1000ms输出一次gc和堆情况,共输出10次
jstat -gcutil 1000 10 # 每隔1000ms输出一次gc和堆的已使用百分比,共输出10次。utilization 利用率
jstat -gcnewcapacity 1000 10 # 输出gc和年轻代的情况
其他用法请自行百度搜索jstat详细用法

  • jmap:可用于查看堆整体情况、对象的histogram图、类加载器统计信息、finalizer的信息、dump出堆转储文件。

jmap -dump:live,format=b,file=heap.hprof

  • jhat:对堆转储文件进行分析,可以查看所有类、所有类的实例数量、GC Roots能到达的对象、堆实例histogram图、支持OQL(Object Query Language)。
  • jstack:查看某个java进程的所有的线程的堆栈信息、每个线程的锁信息。能发现死锁。
  • mat(memory analizer tool):对堆转储文件进行分析,可以查看堆实例histogram图、每个对象到GC Roots的链、内存泄漏分析等。内存泄露分析很强大。推荐使用。
  • arthas:阿里开源的java诊断程序,功能丰富强大,能方便的监控某个方法、发现死锁、热更新代码等。推荐使用。
  • jvisualvm:可查看启动参数、系统属性、cpu的情况、加载、卸载的类的情况、线程数量、堆空间情况、元空间的情况、动态采用堆对象的histogram图。可以下载其他插件来丰富功能,如visualgc插件运行动态可视化观察堆的各个区域的变化。
  • jprofiler:收费软件。优秀的java性能分析器。能查看cpu、堆、线程、类等的整体情况。能筛选出增量的堆对象,并对增量的对象进行分析,是jprofiler的一大特色。能动态观察monitor和锁的情况。能观察实时堆对象、能创建堆快照并进行分析。还有很多功能,十分强大。

参数

-XX被称为不稳定参数,对该类型参数的设置对jvm的性能有较大影响。
-XX语法规则
布尔值
-XX:+ 设置该参数值为true
-XX:- 设置该参数值为false
数字、字符串值
-XX:<param-name>=<value>

参数 作用 示例
-Xms 指定初始堆大小 -Xms100m、-Xms4g
-Xmx 指定堆的上限大小,推荐设置为和-Xmn一样,若大于-Xmn,则jvm会根据需要动态调整堆大小,而这需要额外的性能开销 -Xmx100m、-Xmx4g
-Xmn 指定年轻代的大小 -Xmn100m
-Xss 指定虚拟机栈的大小 -Xss100m
-XX:NewRatio=n 指定年轻代和老年代的比例,年轻代:老年代=1:n -XX:NewRatio=6
-XX:SurvivorRatio=n 指定Eden区和Survivor区的比例,Eden区:Survivor 1: Survivor 2=n:1:1 -XX:SurvivorRatio=5
-XX:+HeapDumpOnOutOfMemory 开启发生OOM时dump出堆转储文件 -XX:+HeapDumpOnOutOfMemory
-XX:HeapDumpPath 指定堆转储文件的位置 -XX:HeapDumpPath=<path>
-Xloggc 适用于jdk8及之前,指定gc日志保存位置。适用于jdk8及之前开启gc日志,需要-Xloggc和-XX:+PrintGC -Xloggc:<path>
-Xlog:gc*:file=<path> jdk9及以后开启gc日志
-XX:+PrintGC 开启打印GC简单日志
-XX:+PrintGCDetails 开启打印gc详细日志
-XX:MaxMetaspaceSize 设置元空间的上限大小 -XX:MaxMetaspaceSize=100m
-XX:MaxTenuringThreshold 年轻代中的对象晋升到老年代的年龄门槛 -XX:MaxTenuringThreshold=20
-XX:+UseParallel 年轻代使用PS收集器
-XX:+UseParallelOldGC 老年代使用PS收集器
-XX:ParallelGCThreads PS收集器的gc线程数 -XX:ParallelGCThreads=5
-XX:MaxGCPauseMillis gc的最大停顿时间
-XX:MaxDirectMemorySize 设置直接内存的大小。当报OutOfMemoryError: direct buffer memory时调大这个值 -XX:MaxDirectMemorySize4g
-XX:+DisableExplicitGC 禁止运行期显示调用System.gc()

案例

用户线程CPU占用过高

一般是代码问题,出现了死循环。

示例代码

public void 
  • 5
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值