字节码指令篇
记住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.如何合理配置堆大小