命令

jps:查看 Java 进程概述,安装了 java 就有
Jinfo pi :查看指定 pid 的所有 JVM 信息

  • jinfo -flags pid 查询虚拟机运行参数信息。
  • jinfo -flag name pid,查询具体参数信息,如 jinfo -flag UseSerialGC 42324,查看是否启用 UseSerialGC

六、VisualVM 的使用 - 图1

jmap
1)jmap -heap pid:输出堆内存设置和使用情况(JDK11 使用 jhsdb jmap —heap —pid pid)
2)jmap -histo pid:输出 heap 的直方图,包括类名,对象数量,对象占用大小
3)jmap -histo:live pid:同上,只输出存活对象信息
4)jmap -clstats pid:输出加载类信息
5)jmap -help:jmap 命令帮助信息
6)jmap -dump:file=a 10340:jmap 下载堆信息文件,查看信息需要下载专门的工具
jstat 每个一定时间监控内存使用情况
jstat -gctil 进程号 时间间隔
百分比显示
六、VisualVM 的使用 - 图2

不想显示百分比,直接不加时间间隔,打印当前使用情况
六、VisualVM 的使用 - 图3

jstack 命令
打印线程信息
jconsole:图形化查看内存线程等信息
六、VisualVM 的使用 - 图4

选择需要查看的进程进行连接
六、VisualVM 的使用 - 图5

VisualVM 安装插件

VisualGC 插件

我们可以通过找到安装 JDK 的目录
六、VisualVM 的使用 - 图6

或者使用 cmd 命令来打开图形化界面
jvisualvm
启动完成后,会有这样一个界面
六、VisualVM 的使用 - 图7

这就代表 Java VisualVM 启动成功
安装 VisualGC 插件
VIsualGC 插件,是能够让我们通过图形化的页面,来查看我们的堆内存,以及各区使用情况
下载插件
首先我们需要到 Visual 的 插件官网 下载,我们需要找到自己的 JDK 版本
比如我的是 JDK1.8,那么我就选择这里
六、VisualVM 的使用 - 图8

然后在找到 VisualGC 插件
六、VisualVM 的使用 - 图9

下载完成后,我
C:\Users\Administrator\AppData\Roaming\VisualVM
六、VisualVM 的使用 - 图10

安装
然后在到我们刚刚打开的 Visual VM 图形化页面,点击工具 -> 插件
六、VisualVM 的使用 - 图11

然后在点击已下载 -> 添加插件
六、VisualVM 的使用 - 图12

找到刚刚我们的这个文件,然后选择安装
六、VisualVM 的使用 - 图13

安装成功后,我们通过写一个代码来进行检测
设置启动的 JVM 参数
-Xms100m -Xmx100m
最后点击 Visual GC 查看我们的堆内存情况
六、VisualVM 的使用 - 图14

工具 MAT

性能分析的主要方式

查看是哪个类占用内存比较高
六、VisualVM 的使用 - 图15

可以使用 visualVM 打开下载好的 dump 信息
自动下载 dump 信息参数
XX:+heapDumpOnOfMermoryError

Linux 上调优工具 Arthas

下载包,直接 jar 运行
java -jar arthas-boot.jar
六、VisualVM 的使用 - 图16

直接显示出正在运行的 Java 进程
输入命令 dashboard 显示线程执行情况,
六、VisualVM 的使用 - 图17

线程 8 占用过高不正常
直接输入 thread 8
直接定位到哪一行导致内存 CPU 占用过高
六、VisualVM 的使用 - 图18

调优:尽可能减少 GC 特别是 Full GC,因为它会导致 stop the World
正常几天出现一次 Full GC 正常,几分钟出现一次明显异常
提交订单时创建订单对象,
六、VisualVM 的使用 - 图19

可能在 14 秒时的部分对象并没有变成垃圾对象,此时部分对象就会转移到 Survice 区,甚至部分对象直接转移到老年代
老年代总共 2G,很快也会被放满
调优方案一:调整各个区的大小,当从 eden 区转移到 S 区时,并不会高于其一半,所以不会产生转移到老年代的情况,故下次的 minorGC 就会将 S0 区的对象也回收,故不会产生 FullGC
六、VisualVM 的使用 - 图20

单机几十万并发的系统 JVM 的优化
当 Eden 去调的很大,也需要优化 minorGC

结合垃圾收集器调优

因为 Eden 与 S0 区是 8:1:1 的时候,Eden 区的东西放到 S 区放不下,还是得放到 old 区,而且 Eden 区的内存大,还得必须对 minorGC 进行优化。
让其每次不让他每次都回收全部的 Eden 区,每次只回收 Eden 的一部分区域,
使用 G1 回收器

实用 VisualVM 进行方法优化

项目中的某一个接口,在某一场景下(数据量大),性能让人难以忍受。
使用 Visual VM 分析某个接口的性能的方法如下:
六、VisualVM 的使用 - 图21

结果显示如下:
六、VisualVM 的使用 - 图22

通过上图,我们可以看到比较耗时的方法为 resolveBytePosition 和 rest,getFile 和 currentUser 是网络请求,暂不考虑。
Plumbr
JVM 检测工具,但是要企业邮箱注册

调优经验

JVM 配置方面,一般情况可以先用默认配置(基本的一些初始参数可以保证一般的应用跑的比较稳定了),在测试中根据系统运行状况(会话并发情况、会话时间等),结合 gc 日志、内存监控、使用的垃圾收集器等进行合理的调整,当老年代内存过小时可能引起频繁 Full GC,当内存过大时 Full GC 时间会特别长。
那么 JVM 的配置比如新生代、老年代应该配置多大最合适呢?答案是不一定,调优就是找答案的过程,物理内存一定的情况下,新生代设置越大,老年代就越小,Full GC 频率就越高,但 Full GC 时间越短;相反新生代设置越小,老年代就越大,Full GC 频率就越低,但每次 Full GC 消耗的时间越大。建议如下:

  • -Xms 和-Xmx 的值设置成相等,堆大小默认为-Xms 指定的大小,默认空闲堆内存小于 40%时,JVM 会扩大堆到-Xmx 指定的大小;空闲堆内存大于 70%时,JVM 会减小堆到-Xms 指定的大小。如果在 Full GC 后满足不了内存需求会动态调整,这个阶段比较耗费资源。
  • 新生代尽量设置大一些,让对象在新生代多存活一段时间,每次 Minor GC 都要尽可能多的收集垃圾对象,防止或延迟对象进入老年代的机会,以减少应用程序发生 Full GC 的频率。
  • 老年代如果使用 CMS 收集器,新生代可以不用太大,因为 CMS 的并行收集速度也很快,收集过程比较耗时的并发标记和并发清除阶段都可以与用户线程并发执行。
  • 方法区大小的设置,1.6 之前的需要考虑系统运行时动态增加的常量、静态变量等,1.7 只要差不多能装下启动时和后期动态加载的类信息就行。

代码实现方面,性能出现问题比如程序等待、内存泄漏除了 JVM 配置可能存在问题,代码实现上也有很大关系:

  • 避免创建过大的对象及数组:过大的对象或数组在新生代没有足够空间容纳时会直接进入老年代,如果是短命的大对象,会提前出发 Full GC。
  • 避免同时加载大量数据,如一次从数据库中取出大量数据,或者一次从 Excel 中读取大量记录,可以分批读取,用完尽快清空引用。
  • 当集合中有对象的引用,这些对象使用完之后要尽快把集合中的引用清空,这些无用对象尽快回收避免进入老年代。
  • 可以在合适的场景(如实现缓存)采用软引用、弱引用,比如用软引用来为 ObjectA 分配实例:SoftReference objectA=new SoftReference(); 在发生内存溢出前,会将 objectA 列入回收范围进行二次回收,如果这次回收还没有足够内存,才会抛出内存溢出的异常。 避免产生死循环,产生死循环后,循环体内可能重复产生大量实例,导致内存空间被迅速占满。
  • 尽量避免长时间等待外部资源(数据库、网络、设备资源等)的情况,缩小对象的生命周期,避免进入老年代,如果不能及时返回结果可以适当采用异步处理的方式等。

实例:
OKhttp 的看门狗线程

转载 https://www.yuque.com/jykss/jykss/qaomdf