JVM性能优化-内存

1,060 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第30天,点击查看活动详情

概述

之前画过一张图,是从Class文件到类装载器,再到运行时数据区的过程。现在把这张图不妨丰富完善一下,展示了JVM的大体物理结构图。

JVM Architecture: 藏宝图

image.png

性能优化

JVM的性能优化可以分为代码层面和非代码层面。

在代码层面,大家可以结合字节码指令进行优化,比如一个循环语句,可以将循环不相关的代码提取到循环体之外,这样在字节码层面就不需要重复执行这些代码了。

在非代码层面,一般情况可以从内存、gc以及cpu占用率等方面进行优化。

注意,JVM调优是一个漫长和复杂的过程,而在很多情况下,JVM是不需要优化的,因为JVM本身已经做了很多的内部优化操作。

那就从内存、gc以及cpu这3个方面和大家一起探讨一下JVM的优化,但是要注意的是不要为了调优和调优。

内存

内存分配

正常情况下不需要设置,那如果是促销或者秒杀的场景呢?

每台机器配置2c4G,以每秒3000笔订单为例,整个过程持续60秒。

image.png

内存溢出(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