持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第30天,点击查看活动详情
概述
之前画过一张图,是从Class文件到类装载器,再到运行时数据区的过程。现在把这张图不妨丰富完善一下,展示了JVM的大体物理结构图。
JVM Architecture: 藏宝图
性能优化
JVM的性能优化可以分为代码层面和非代码层面。
在代码层面,大家可以结合字节码指令进行优化,比如一个循环语句,可以将循环不相关的代码提取到循环体之外,这样在字节码层面就不需要重复执行这些代码了。
在非代码层面,一般情况可以从内存、gc以及cpu占用率等方面进行优化。
注意,JVM调优是一个漫长和复杂的过程,而在很多情况下,JVM是不需要优化的,因为JVM本身已经做了很多的内部优化操作。
那就从内存、gc以及cpu这3个方面和大家一起探讨一下JVM的优化,但是要注意的是不要为了调优和调优。
内存
内存分配
正常情况下不需要设置,那如果是促销或者秒杀的场景呢?
每台机器配置2c4G,以每秒3000笔订单为例,整个过程持续60秒。
内存溢出(OOM)
一般会有两个原因:
(1)大并发情况下
(2)内存泄露导致内存溢出
大并发[秒杀]
-
浏览器缓存、本地缓存、验证码
-
CDN静态资源服务器
-
集群+负载均衡
-
动静态资源分离、限流[基于令牌桶、漏桶算法]
-
应用级别缓存、接口防刷限流、队列、Tomcat性能优化
-
异步消息中间件
-
Redis热点数据对象缓存
-
分布式锁、数据库锁
-
5分钟之内没有支付,取消订单、恢复库存等
内存泄露导致内存溢出
ThreadLocal引起的内存泄露,最终导致内存溢出
public class TLController {
@RequestMapping(value = "/tl")
public String tl(HttpServletRequest request) {
ThreadLocal<Byte[]> tl = new ThreadLocal<Byte[]>();
// 1MB
tl.set(new Byte[1024*1024]);
return "ok";
}
}
(1)上传到阿里云服务器
jvm-case-0.0.1-SNAPSHOT.jar
(2)启动
java -jar -Xms1000M -Xmx1000M -XX:+HeapDumpOnOutOfMemoryError - XX:HeapDumpPath=jvm.hprof jvm-case-0.0.1-SNAPSHOT.jar
(3)使用jmeter模拟10000次并发
39.100.39.63:8080/tl
(4)top命令查看
top
top -Hp PID
(5)jstack查看线程情况,发现没有死锁或者IO阻塞的情况
jstack PID java -jar
arthas.jar ---> thread
(6)查看堆内存的使用,发现堆内存的使用率已经高达88.95%
jmap -heap PID
java -jar arthas.jar ---> dashboard
(7)此时可以大体判断出来,发生了内存泄露从而导致的内存溢出,那怎么排查呢?
jmap -histo:live PID | more
获取到jvm.hprof文件,上传到指定的工具分析,比如heaphero.io