1.JVM优化什么
由博客JVM之垃圾回收-CSDN博客我们已经了解到了数据存储是在方法区和堆区,而堆区的使用更为频繁。堆区有什么呢?老年代、新生代、GC。因此JVM性能优化,优化什么? 我们猜想一下,新生代的大小设置;老年代的大小设置;新生代到老年代的阈值设置;GC算法;大对象的存放阈值;无外乎是这么几种,于是我们带着这么些个问题来进一步探讨
2.JVM常用命令和工具
jps 查看进程id
jinfo主要是查看JVM的配置参数
jinfo ‐ flag name PID
jinfo ‐ flag < name >=< value > PID
jinfo ‐ flags PID
jstat主要是做统计 -gc统计垃圾回收的次数
jstat ‐ class PID 1000 10 查看某个 java 进程的类装载信息,每 1000 毫秒输出一次,共输出 10 次
jstat ‐ gc PID 1000 10
jstack PID 查看JVM的详细堆栈信息
jmap ‐ heap PID 查看堆栈信息
2 jmap ‐ dump : format = b , file = heap . hprof PID
3 ‐ XX : + HeapDumpOnOutOfMemoryError ‐ XX : HeapDumpPath = heap . hprof # 可以设置内存溢出时,自动导出文件
JDK通用工具:
jconsole: JDK自带的可视化监控工具。查看java应用程序的运行概况、监控堆信息、永久区使用情况、类加载情况等。
jvisualvm: 可以监控某个java进程的CPU,类,线程等
内存分析工具:
MAT: java堆分析器,用于查找内存泄漏
HeapHero : Brilliant Graphs, metrics and java heap dump analysis anti-patterns reported (heaphero.io)
Perfma:https://console.perfma.com/
GC分析工具:
GC日志:可以使用不同的参数设置不同的日志文件,比如:
‐XX:+PrintGCDetails ‐XX:+PrintGCTimeStamps ‐XX:+PrintGCDateStamps ‐Xloggc:D:\gc.log
gcviewer
java ‐jar gcviewer‐1.36‐SNAPSHOT.jar
gceasy Universal JVM GC analyzer - Java Garbage collection log analysis made easy (gceasy.io)
3.JVM性能优化
JVM的性能优化可以分为代码层面和非代码层面的。
在代码层面,大家可以结合字节码指令,内存是否浪费等进行优化,比如一个循环语句,可以将循环不相关的代码提取到循环体之外,这样在字节码层面就不需要重复执行这些代码了。
在非代码层面,一般情况可以从参数、内存、GC以及CPU占用率等方面进行优化。
注意:JVM调优是一个漫长和复杂的过程,而在很多情况下,JVM是不需要优化的,因为JVM本身已经做了很多内部优化操作,千万不要为了调优而调优。
3.1 代码优化
再举一个例子,比如一个ArrayList,初始容量为10,而我们是需要添加11个元素的,假设我们添加到了第11个元素,则就触发了ArrayList的扩容,扩容到了15,而我们只使用了11个内存空间,剩下的4个是不是就内存浪费了,因此我们在初始化的时候,如果确定知道了List的大小,则直接进行初始化,对内存资源的合理利用。
3.2 参数优化
参数官网: java (oracle.com)
( 1 ) ‐ XX : MaxTenuringThreshold
Sets the maximum tenuring threshold for use in adaptive GC sizing . The largest value is 15. The default value is 15 for the parallel ( throughput ) collector , and 6 for the CMS collector .
( 2 ) ‐ XX : PretenureSizeThreshold
超过多大的对象直接在老年代分配,避免在新生代的Eden 和 S 区不断复制
( 3 ) ‐ XX : +/‐ UseAdaptiveSizePolicy
Enables the use of adaptive generation sizing . This option is enabled by default .
( 4 ) ‐ XX : SurvivorRatio
默认值为 8
( 5 ) ‐ XX : ConcGCThreads
Sets the number of threads used for concurrent GC . The default value depends on the number of CPUs available to the JVM .
(6 ) ‐ Xsssize
Sets the thread stack size ( in bytes ). Append the letter k or K to indicate KB
( 7 ) ‐ Xms 和 ‐ Xmx
两者值一般设置成一样大,防止内存空间进行动态扩容
( 8 ) ‐ XX : ReservedCodeCacheSize
Sets the maximum code cache size ( in bytes ) for JIT ‐ compiled code . Append the letter k or K to indicate kilobytes , m or M to indicate megabytes , g or G to indicate gigabytes .
3.3 内存调优
举个案例:
假设每台机器配置2C4G,以每秒3000笔订单为例,整个过程持续60秒(大并发场景下)
假设我们订单的对象Order为1kb,则每秒1000个订单就是1000kb,又假设我们这个订单对象有非常多的关联对象,大概有30个,则每秒中所占用的内存就是30M。2C4G的配置,堆内存为4000MB,默认Young:Old = 1:2 所以young区大约为1333MB;大概过了45秒左右,young区就不够用了,就回去增加old的压力,最终不仅会发生young GC 还有可能发生Old GC。怎么解决?增加机器? No 可以此时将young:old设置成2:1 这样一来,young区大概就会有2666MB了。
内存泄漏导致内存溢出的问题排查:
01 启动
java ‐ jar ‐ Xms1000M ‐ Xmx1000M ‐ XX : + HeapDumpOnOutOfMemoryError ‐ XX : HeapDumpPath = jvm . hprof jvm ‐ case ‐ 0.0.1 ‐ SNAPSHOT . ja r
02 使用 jmeter 模拟并发
03 使用 top 命令查看
top
top ‐ Hp PID
04 jstack 查看有没有死锁或者 IO 阻塞
jstack PID
05 查看堆内存使用情况
jmap ‐ heap PID
java ‐ jar arthas . jar ‐‐‐> dashboard
06 获取到 heap 的文件,比如 jvm . hprof ,用相应的工具来分析,比如 heaphero . io
3.4 CPU占用率过高
( 1 ) top
( 2 ) top ‐ Hp PID
查看进程中占用 CPU 高的线程 id ,即 tid
( 3 ) jstack PID | grep tid ( 1 ) top
3.5 GC调优
重点分析G1垃圾收集器(因为G1垃圾收集器是分成了各个region 设置的参数比较多)
(1)使用 G1 GC垃圾收集器,获取到日志文件:-Xms100M -Xmx100M
(2)调整堆内存大小:-Xms300M -Xmx300M
(3)调整最大停顿时间:-XX:MaxGCPauseMillis=200 设置最大GC停顿时间指标
(4)启动并发GC时堆内存占用百分比:-XX:InitiatingHeapOccupancyPercent=45
G1用它来触发并发GC周期,基于整个堆的使用率,而不只是某一代内存的使用比例。值为0则表示"一直执行GC循环". 默认值为 45 (例如, 全部的 45% 或者使用了45%)