基于场景的JVM调优

落日映苍穹つ 2023-02-23 08:12 59阅读 0赞

基于场景的JVM调优

前言

我们在面试大厂的Java开发岗位的时候有一个问题经常会被问到,你在开发的过程中有没有遇到JVM的参数的相关问题,本篇博客就带领大家去了解几个常见的JVM的现象以及解决方法。

JVM的其它知识可参考我的博客—蹊源的Java笔记—JVM

正文

内存泄漏与内存溢出

异常堆栈信息“java.lang.OutOfMemoryError:java heap space

  • 内存泄漏:指的是程序在动态分片一些临时对象,但是对象不会被GC正常回收。它始终占用内存。即对象可达但已无用(诸如缓存)
  • 内存溢出:指程序运行过程中无法申请到足够的内存而导致的一种错误。

所以内存泄漏只是内存溢出的一个可能诱发原因。

内存泄漏的常见场景

  1. 长生命周期的对象持有短生命周期对象的引用。(这是最常见的情况)
  2. 修改hashset对象的参数值,且参数是计算hash值得字段(这个hash对象已经不可获取,但又没正常被gc)
  3. 机器的连接数和关闭时间设置(可以联想平安系统在连接多个数据库连接时,包内存溢出问题)
  4. 线程池使用了无界队列,请求短时时间大量涌入,没有足够的线程去处理任务。

内存溢出的常见场景

  1. 堆内存溢出:当频繁生产新新对象时,内存占用量超出jvm分配的内存。
  2. 方法区溢出:程序加载的类过多,或者使用反射等动态代理生成类的技术,就可能导致该区发生内存溢出。
  3. 线程栈溢出:一般线程栈溢出,是由于递归太深或者方法调用层级过多导致的。

在生产环境如何去解决内存溢出的问题:

  • 在jar的启动参数添加: -XX:+heapDumpOnOutofMemoryError
  • 可以让虚拟机在出现内存溢出异常时Dump出当前的内存堆转储快照以便事后进行分析。

手段:通过内存映射分析工具(如Eclipse Memory Analyzer

核心:通过判断内存中的对象是否是必要来判断是不是内存泄漏(即这对象是否是可达有用的)

现象一:CPU瞬间被占满

第一步top -c 查看当前占用CPU比较高的进程

top指令的参数

  • d:指定更新的间隔,以秒计算。
  • q:没有任何延迟的更新。如果使用者有超级用户,则top命令将会以最高的优先序执行。
  • c:显示进程完整的路径与名称。
  • S:累积模式,会将己完成或消失的子行程的CPU时间累积起来。
  • s:安全模式。
  • i:不显示任何闲置(Idle)或无用(Zombie)的行程。
  • n:显示更新的次数,完成后将会退出top

第二步top -Hp 进程号 获取该进程下,线程的占用的情况
在这里插入图片描述

这里的pid是10进制的,我们需要获取其16进制的
进制转换:7390 ——>1cde

第三步jstack 导出进程快照

  1. #在当前路径下导出进程快照
  2. jstack -l 7390 > ./7390.stack
  3. #获取占用线程比较高的线程的相关输出
  4. cat 7390.stack |grep '1cde' -C 8

现象二:内存溢出(OOM)

通常对dump文件(进程的内存镜像)进行分析

获取dump文件的方式:
1.添加jar启动参数 在发生OutOfMemoryError时生成dump文件 (通常来说dump相对比较大)

  1. -XX:+HeapDumpOnOutOfMemoryError(程序内存溢出自动转存dump)
  2. -XX:HeapDumpPath=D:\sso\dump(转成dump文件路径)

2.使用jmap获取,如获取 32652的dump

  • jmap可以导出jvm中存活对象的堆内存信息
  • jstack可以导出此进程的堆栈信息
  • jmap只能用比较小的项目,一般生产环境不能使用jmap,需要比较长的时间

    jmap -dump:format=b,file=./32652.hprof 32652

3.使用专门的工具对dump文件进行分析

  • 使用JDK自带的 jvisualvm 工具可以分析dumpwen List item

在这里插入图片描述

现象三:系统卡顿

首先我们要知道系统卡顿是由于GC导致的。

GC对程序产生影响的情况:(影响从高到低)

  • FGC过于频繁FGC通常是比较慢的,少则几百毫秒,多则几秒,正常情况FGC每隔几个小时甚至几天才执行一次,对系统的影响还能接受。
  • YGC耗时过长:一般来说,YGC的总耗时在几十或者上百毫秒是比较正常的,虽然会引起系统卡顿几毫秒或者几十毫秒,这种情况几乎对用户无感知,对程序的影响可以忽略不计。
  • FGC耗时过长FGC耗时增加,卡顿时间也会随之增加,尤其对于高并发服务,可能导致FGC期间比较多的超时问题,可用性降低,这种也需要关注。
  • YGC过于频繁:即使YGC不会引起服务超时,但是YGC过于频繁也会降低服务的整体性能,对于高并发服务也是需要关注的。

使用jstat查看虚拟机的GC情况

  1. jstat -gcutil 7378
  2. S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
  3. 0.00 2.66 77.68 91.77 91.59 82.62 949 6.188 288438 11884.693 11890.880

参数说明:

  • FGCfull gc的次数
  • FGCTfull gc的总时长

如果单次Full GC过长,可以通过修改提高新生代和老生代的比例、选择合适的GC方式等减少停顿时间。

full gc可能的场景:

  1. 老年代满了,由于内存分配担保策略,当晋升到老年代的对象大于了老年代的剩余空间时,就会触发FGC
  2. 老年代的内存使用率达到了一定阈值(可通过参数调整),直接触发FGC
  3. Metaspace(元空间)在空间不足时会进行扩容,当扩容到了-XX:MetaspaceSize 参数的指定值时,也会触发FGC
  4. System.gc()或者Runtime.gc()被显式调用时,触发FGC
  5. 采用CMS收集器发生"Concurrent Mode Failure”异常时,触发FGC

我们处理fullgc的方式就是分析当时的dump文件,通过分析各区域的内存空间状况,从而定位fullgc的原因。

有两种方式获取fullgc前后dump文件:

  • 通过在jvm里添加参数配置+HeapDumpBeforeFullGC,+HeapDumpAfterFullGC
  • 通过jinfo命令设置VM参数jinfo -flag +HeapDumpBeforeFullGC 进程号 ,jinfo -flag +HeapDumpAfterFullGC 进程号
  • jmap并不能直接用在生产上,因当文件比较大的情况下时间比较长
  • 再获取dump文件后可以通过JDKjvisualvm工具进一步分析

在这里插入图片描述

发表评论

表情:
评论列表 (有 0 条评论,59人围观)

还没有评论,来说两句吧...

相关阅读

    相关 JVM 场景总结

    一、cpu占用过高 cpu占用过高要分情况讨论,是不是业务上在搞活动,突然有大批的流量进来,而且活动结束后cpu占用率就下降了,如果是这种情况其实可以不用太关心,因为请求

    相关 基于场景JVM

    基于场景的JVM调优 前言 我们在面试大厂的`Java`开发岗位的时候有一个问题经常会被问到,你在开发的过程中有没有遇到`JVM`的参数的相关问题,本篇博客就带领大

    相关 jvm

     最近因项目存在内存泄漏,故进行大规模的JVM性能调优 , 现把经验做一记录。 一、JVM内存模型及垃圾收集算法  1.根据Java虚拟机规范,JVM将内存划分为:

    相关 JVM

    一、JVM调优的监控方法 jvm在对进行问题排查,线程等关注问题,在理解jvm的内存分配和垃圾回收,java类的编译和加载等等理论知识的前提下要学会使用工具去观察jvm中的实

    相关 JVM

    1. 年轻代大小选择 (1) 响应时间优先的应用:尽可能设大,直到接近系统的最低响应时间限制(根据实际情况选择)。在此种情况下,年轻代收集发生的频率也是最小的。同时,减少到

    相关 spark JVM

    我们的堆内存分为:新生代,和年老代, 年轻代又分为:Eden区,幸存一区,幸存二区, 每一次访对象的时候,都是放入eden区域,和其中的一个幸存一区中,幸存二区是不放对象的

    相关 JVM

    年轻代大小选择 响应时间优先的应用:尽可能设大,直到接近系统的最低响应时间限制(根据实际情况选择)。在此种情况下,年轻代收集发生的频率也是最小的。同时,减少到达年老代的对

    相关 JVM

    JVM调优是所有初级程序员向高级迈入的必经之路,而这个过程又需要许多JVM内存知识。下面就总结一二,和大家分享一下: 1.JVM内存模型 JVM内存模型如下图所示: