大厂学院 宋红康 JVM 学习笔记

字节码指令篇

记住store(往局部变量表存)  push(往操作数栈里面放)  load(从局部变量表里取到操作数栈)即可

例如:
     Integer x = 128;
     int y = 128;
     System.out.println(x==y);

对应:

 0 sipush 128 //将常量128压栈
 3 invokestatic #2 <java/lang/Integer.valueOf>//对栈顶元素进行方法调用
 6 astore_1//将引用类型地址值放到临时变量表序号为1的位置,即对x赋值
 7 sipush 128//将常量128压栈
10 istore_2//将栈顶元素放入放到临时变量表序号为1的位置
11 getstatic #3 <java/lang/System.out>
14 aload_1//将序号为1的元素入栈
15 invokevirtual #4 <java/lang/Integer.intValue>//拆箱
18 iload_2
19 if_icmpne 26 (+7)
22 iconst_1a
23 goto 27 (+4)
26 iconst_0
27 invokevirtual #5 <java/io/PrintStream.println>
30 return

类加载篇

过程

loading(类加载器)
linking
initialization
using
unloading

双亲委派机制和破坏

类加载器 的 “子父类”(说是子父,实际上不是继承关系,而是声明了一个引用叫parent)分为:

引导类加载器:加载java核心类,由c++编写获取不到
扩展类加载器:加载第三方jar包
系统类加载器:自己编写的应用
自定义类加载器

双亲委派机制:加载类时,会一层层往上找,找到最顶端。再一层层往下看是否能加载。

好处在于:
    避免重复加载,该谁就由谁加载,核心类就由引导类加载器加载,应用类就由系统类加载器加载。

破坏:
    怎么破坏:重写loadclass方法,不走上面一层层委托的流程,就算打破。

    打破案例:比如说 有两个webapp ,都有一个类 叫user,全限定类名都一样 com.xxx.User,但具体实现不一样,Tomcat怎么保证不冲突呢?给每个app都创建了一个类加载器实例,会优先加载当前应用下的类,找不到,再一层层往上尝试加载,这样Tomcat 就保证了 webapp之间的隔离性,
 

内存结构篇

栈的栈帧

主要有局部变量表和操作数栈。
    局部变量表的大小是以“槽”的数量确定的,比如64位长度的long和double类型就会站两个槽,所以局部变量表的大小在编译时就确定了。

堆空间的参数设置小结

最小 -Xms  默认物理内存的1/64
最大 -Xmx   默认物理内存的1/4

一般情况下,两者的值都设置为一样,避免GC后频繁去计算堆空间大小,提高性能。常用值为2000MB


-XX:PrintGCDetails

-XX:HandlePromotionFailure 空间分配担保
  注:1.promotion 对象提升(15次minor GC后往往老年代放)
      2.jdk6后默认开启

    首先,minorGC前会检查老年代最大连续可用空间 是否大于新生代所有空间的总大小
    是,minorGC安全
    否,然后就会看是否大于 历次历次晋升的平均值
    是,仍可以minorGC
    否,fullGC

对象分配原则(堆中)

大对象和长期存活的对象直接分配到老年代

survivor空间的中 有相同年龄的对象达到s区的一半,那么大于或等于该年龄的对象直接进入老年代。

oom如何解决

通过工具 看是否是内存泄漏还是内存溢出
    内存泄漏的话,就要用工具看 无法回收的泄漏对象跟GC Roots的引用链  定位到代码
    内存溢出,调大堆空间

jdk7和8在jvm的区别(元空间取代永久代)

为什么这样干?
    因为元空间直接使用的是本地内存,可以加载更多class文件,避免频繁oom(试想,方法区 本来就基本不GC 若是需要加载的class文件又多 将可用的堆空间会挤压多严重)

对象创建的过程(*****)

1.对应的类是否加载了。

2.分配空间:    
    指针碰撞:内存规整的话,移动指针
    空闲列表:内存不规整,从列表中找一个够大的

3.处理空间分配的并发问题:
    cas:
    tlab:

4.初始化分配到的空间。

5.设置对象头:
    hash值 锁状态 gc存活次数 ; 类型指针

6.执行init进行初始化。

强软弱虚

记忆规律:
    它们为强度递减,记住 软:内存不足就回收,弱:gc就回收,虚:用于跟踪垃圾回收过程

垃圾回收篇

说一下cms过程

concurrent mark sweep:
1.初始标记:标记GCRoots直接相关的对象

2.并发标记:整个对象图
3.重新标记:修正2期间的
4.并发清除

G1

概念:
        与最大cms不同在于:
                不是基于分代或分区的,而是看那块内存占用多就回收那块;

fullgc 干了哪些事

基于整个heap 

  • 1. cms或G1 时  fullgc: serial + serialOld
  • 2. ParallOld时,fullgc: ParallNew + ParallOld

调优案例篇

各种oom的场景

1.堆溢出

  • 报错信息

        java.lang.OutOfMemoryError: Java heap space

  • 案例模拟

         发送请求 http://localhost:8080/add

  • JVM参数配置

                -XX:+PrintGCDetails
                -XX:MetaspaceSize=64m
                -XX:+HeapDumpOnOutOfMemoryError
                -XX:HeapDumpPath=heap/heapdump.hprof
                -XX:+PrintGCDateStamps
                -Xms50M
                -Xmx50M
                -Xloggc:log/gc-oomHeap.logs


                注释掉jdk1.8支持的打印gc日志配置

                <!-- <extraArgument>-XX:+PrintGCDetails</extraArgument> --><!--输出GC的详细日志-->

                <!-- <extraArgument>-XX:+PrintGCDateStamps</extraArgument> --><!--输出GC的时间戳-->

                改成jdk11支持的配置

                <extraArgument>-Xlog:gc*:logs/gc.log:time</extraArgument><!--日志文件的输出路径-->

  • 运行结果
  • 原因及解决方案

        原因: 看是是否有大对象 解决方案: 用jmap命令或配置参数 将堆dump下来, 用MAT分析定位下。

  • dump文件分析

        jvisualvm分析

        MAT分析

  • gc日志分析

2.元空间溢出

  • 报错信息

        java.lang.OutOfMemoryError: Metaspace

  • 案例模拟

        发送请求 http://localhost:8080/metaSpaceOom

  • JVM参数配置

        -XX:+PrintGCDetails
        -XX:MetaspaceSize=40m
        -XX:MaxMetaspaceSize=40m
        -Xss512K
        -XX:+HeapDumpOnOutOfMemoryError
        -XX:HeapDumpPath=heap/heapdumpMeta.hprof
        -XX:SurvivorRatio=8
        -XX:+TraceClassLoading
        -XX:+TraceClassUnloading
        -XX:+PrintGCDateStamps
        -Xms40M
        -Xmx40M
        -Xloggc:log/gc-oomMeta.log

  • 运行结果
  • 原因及解决方案

        原因:
            1.存在大量的代理对象,方法区打满了
            2.元空间内存本身过小

        解决方案:
            用jmap命令或配置参数  将堆dump下来, 用MAT检查是否有大量反射产生的代理对象。

  • dump文件分析

        jvisualvm分析

        MAT分析

  • gc日志分析

3.GC overhead limit exceeded

  • 报错信息

        java.lang.OutOfMemoryError: GC overhead limit exceeded

  • 案例模拟
  • JVM参数配置

        -XX:+PrintGCDetails
        -XX:+HeapDumpOnOutOfMemoryError
        -XX:HeapDumpPath=heap/dumpExceeded.hprof
        -XX:+PrintGCDateStamps
        -Xms10M
        -Xmx10M
        -Xloggc:log/gc-oomExceeded.log

  • 运行结果
  • 原因及解决方案

        原因:
           频繁GC缺回收不到2%的内存
           当我们 XX:-UseGCOVerheadLimit时,最终仍会报:java.lang.OutOfMemoryError:         Java heap space,可以认为是后者的前置检查

        解决方案:
            用jmap命令或配置参数  将堆dump下来, 用MAT检查是否有大对象。

  • dump文件分析

        jvisualvm分析

        MAT分析

优化案例一:调整堆大小,提升吞吐量

测试tomcat服务

原配置  

setenv.sh文件中写入:

export CATALINA_OPTS="$CATALINA_OPTS -Xms30m"
export CATALINA_OPTS="$CATALINA_OPTS -XX:SurvivorRatio=8"
export CATALINA_OPTS="$CATALINA_OPTS -Xmx30m"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+UseParallelGC"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+PrintGCDetails"
export CATALINA_OPTS="$CATALINA_OPTS -XX:MetaspaceSize=64m"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+PrintGCDateStamps"
export CATALINA_OPTS="$CATALINA_OPTS -Xloggc:/opt/apache-tomcat-8.5.87/logs/gc.log"

优化配置

export CATALINA_OPTS="$CATALINA_OPTS -Xms120m"
export CATALINA_OPTS="$CATALINA_OPTS -XX:SurvivorRatio=8"
export CATALINA_OPTS="$CATALINA_OPTS -Xmx120m"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+UseParallelGC"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+PrintGCDetails"
export CATALINA_OPTS="$CATALINA_OPTS -XX:MetaspaceSize=64m"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+PrintGCDateStamps"
export CATALINA_OPTS="$CATALINA_OPTS -Xloggc:/opt/apache-tomcat-8.5.87/logs/gc.log"

优化案例二:JIT(后端编译器,编译整个函数为一条指令,避免逐行解释执行) 逃逸分析:栈上分配,同步消除,标量替换

优化案例三:合理配置堆内存

堆内存 为 在full gc后 老年代存活对象占比的 3x - 4x

优化案例四:cpu飙高

优化案例五:G1并发GC线程数对性能的影响

测试tomcat服务

原配置  
setenv.sh文件中写入:
export CATALINA_OPTS="$CATALINA_OPTS -XX:+UseG1GC"
export CATALINA_OPTS="$CATALINA_OPTS -Xms30m"
export CATALINA_OPTS="$CATALINA_OPTS -XX:SurvivorRatio=8"
export CATALINA_OPTS="$CATALINA_OPTS -Xmx30m"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+PrintGCDetails"
export CATALINA_OPTS="$CATALINA_OPTS -XX:MetaspaceSize=64m"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+PrintGCDateStamps"
export CATALINA_OPTS="$CATALINA_OPTS -Xloggc:/opt/apache-tomcat-8.5.87/logs/gc.log"
export CATALINA_OPTS="$CATALINA_OPTS -XX:ConcGCThreads=1"

优化配置

线程数改为2,增加吞吐量

优化案例六:调整垃圾回收器 对吞吐量的影响

测试tomcat服务

原配置  

setenv.sh文件中写入:

export CATALINA_OPTS="$CATALINA_OPTS -Xms60m"
export CATALINA_OPTS="$CATALINA_OPTS -Xmx60m"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+UseParallelGC"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+PrintGCDetails"
export CATALINA_OPTS="$CATALINA_OPTS -XX:MetaspaceSize=64m"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+PrintGCDateStamps"
export CATALINA_OPTS="$CATALINA_OPTS -Xloggc:/opt/apache-tomcat-8.5.87/logs/gc.log"

优化配置

改成XX:+UseG1GC

优化案例七:日均百万订单系统 如何调优

计算每秒的对象大小,就可计算出 多久将新生代填满(即多久发生一次miniorgc),将此时长 和 订单处理时长 比较,若小于则会有大量对象进入老年代

小结

1.提升吞吐量 (调整堆大小,换G1垃圾回收器和并发的垃圾回收线程数)

2.如何合理配置堆大小

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值