Java虚拟机
2020-06-22 11:41:50 0 举报
AI智能生成
jvm知识体系
作者其他创作
大纲/内容
Java虚拟机
字节码
字节码文件
字节码主要指令
1、加载或储存指令
1、将局部变量加载到操作栈中
ILoad:将int类型的局部变量压入栈
ALoad:将对象引用的局部变量压入栈
2、从操作栈顶存储到局部变量表
ISTORE、ASTORE等
3、将常量加载到操作栈顶(极为高频使用的指令)
ICONST:加载-1-5的数
BIPUSH(Byte Immediate PUSH):加载-128-127之间的数
SIPUSH(Short Immediate PUSH):加载-32768-32767之间的数
LDC(Load Constant):在-2147483648-2147483647或者是字符串时
2、运算指令
IADD、IMUL等
3、类型转换指令
I2L、D2F
4、对象创建和访问指令
创建对象指令:NEW、NEWARRAY等
访问属性指令:GETFIELD、PUTFIELD、GETSTATIC等
检查实例类型指令:INSTSNCEOF、CHECKCAST等
5、操作栈管理指令
出栈操作:POP、POP2
复制栈顶元素并压入栈:DUP
6、方法调用与返回指令
INVOKEVIRTUAL:调用对象的实例方法
INVOKESPECIAL:调用实例初始化方法、私有方法、父类方法等
INVOKESTATIC:调用类静态方法
RETURN:返回VOID类型
7、同步指令
MONITORENTER、MONITOREXIT
源码转换字节码
字节码执行
解释执行
JIT编译执行
JIT编译和解释耦合执行
类加载过程
第一步,Load(加载)
Load阶段读取类文件产生的二进制流,并转化为特定的数据结构,初步校验cafe babe魔法数、常量池、文件长度、是否有父类等,让后创建java.lang.Class实例
第二步,Link (链接)
第一步,验证
验证是更详细的校验,比如final是否合规、类型是否正确、静态变量是否合理等
第二步,准备
准备阶段是为静态变量分配内存,并设定默认值
第三步,解析
解析类和方法确保类与类之间的相互引用正确性,完成内存结构布局
第三步,Init(初始化)
Init阶段执行类构造器<clinit>方法,如果赋值运算是通过其他类的静态方法来完成的,那么会马上解析另外一个类,在虚拟机栈中执行完毕后通过返回值进行赋值
Class
它是所有class的类,“类中之王”
类加载方式
Parents Delegation Model(双亲/溯源委派加载模型)
Bootstrap
JVM启动是创建,通常由与操作系统相关的本地代码实现,是最根基的类加载器。负责装载最核心的Java类,如:Object、System、String等
EXtension ClassLoader(java9之前)/Platform ClassLoader
加载扩展的系统类,java语言实现,如:XML、加密、压缩先相关的功能类等
Application ClassLoader
主要是用户自定义的CLASSPATH路径下的类,java语言实现
自定义类加载器
1、隔离加载类。在某些框架内进行中间件与应用的模块隔离,把类加载到不同的环境
2、修改类加载方式。类的加载模型并非强制,除Bootstrap外,其他的加载并非一定要引入,或者根据实际情况在某个时间点按需进行动态加载
3、扩展加载源。比如从数据库、网络
4、防止源码泄露。Java代码容易被编译和篡改,可以进行编译加密。那么类加载器也需要自定义,还原加密的字节码
对象实例化
JVM内存布局
1、Heap(堆区)
Young区(新生代)
Eden
S0
S1
Old区(老年代)
2、Metespace(元空间)
过期命令
MaxpermSize=1024M
存储信息
在JDK8里,Perm区中的所有内容中的字符串常量移至堆内存(坑,这个改动会造成:同样的代码,在jdk7和jdk8环境下运行结论不同),其他内容包括类元信息、字段、静态属性、方法、常量等都移动至元空间内。比如:Object类元信息、静态属性System.out、整形常量100000000等。常量池中的String,实际对象是存储在堆内存的
3、JVM Stack(虚拟机栈)
1、局部变量表
局部变量表是存放方法参数和局部变量的区域。字节码指令STORE指令就是将操作栈中计算完成的局部变量写会局部变量表的存储空间
2、操作栈
操作栈是一个初始化状态为空的桶式结构栈
3、动态链接
每个栈帧中包含一个在常量池中对当前方法的引用,目的是支持方法调用过程的动态连接
4、方法返回地址
方法退出两种情况:1、正常退出,如RETURN、IRETURN、ARETURN等;异常退出。无论何种退出,都将返回至方法当前被调用的位置。
方法退出的三种情况
返回值压入上层调用栈帧
异常信息抛给能处理的栈栈帧
PC计数器指向方法调用后的下一条指令
4、本地方法栈
本地方法栈为Native方服务。线程开始调用本地方法时,会进入一个不受JVM约束的世界。本地方法可以通过JNI(Java Native Interface)来访问虚拟机运行时数据区,甚至可以调用寄存器,具有和JVM相同的能力和权限。对于内存不足的情况,会抛出native Heap OutOfMedmory
著名的本地方法有Symtem.ccurrentTimeMilis();
5、Prpgram Counter Redister(程序计数器)
存放执行指令的偏移量和行号指示器等,线程执行或恢复都要依赖程序计数器
JVM参数类型
参数类型
标准参数
一般在不同的jvm版本中都不会变,-help、-server、-client、-version、-showversion、-cp、-classpath
-X参数
非标准化参数,在不同jvm版本里不会有太大变化,
-Xint(解释执行)
-Xcomp(第一次使用就编译成本地代码)
-Xmixed(混合模式,JVM来决定是否编译成本地代码)
XX参数
Boolean类型
格式:-XX:[+-]<name> 表明禁用或者启用name的属性
比如:-XX:+UseConcMarkSweepGC、-XX:+UseG1GC
非Boolean类型(key-value类型)
格式:-XX:<name>=<value> 表示name的属性值是value
-XX:MaxGCPauseMillis=500、XX:GCTimeRatio=19
易混命令
-Xms
等价于-XX:InitialHeapSize=2048
-Xmx
等价于-XX:MaxHeapSize=2048
-Xss
等价于-XX:ThreadStackSize=512
JVM参数
GC(垃圾回收)
GC原理
GC如何判断对象是否可以被回收
JVM引入GC Roots。如果对象与GC Roots之间没有直接或间接的引用关系,是可以被回收的
GC Roots
类静态属性中引用的对象
常量引用的对象
虚拟机栈中引用的对象
本地方法栈中引用的对象等
GC算法
标记-清除算法
标记-整理算法
Mark-Copy算法
分代垃圾回收
Young用复制算法
Old取用标记-清除算法或者标记-整理算法
GC
1.新生代垃圾收集器
Serial(jdk1.3)
1.单线程,只开启一条线程进行垃圾回收,并在垃圾回收过程中停止一切用户线程,从而用户请求或图形化界面会出现卡顿
2.适合客户端应用,一般客户端应用所需内存较小,不会创建太多对象,而且堆内存不大,因此垃圾回收的时间比较短
3.简单高效,因为只有一条GC线程,因此避免了切换线程的开销,从而简单高效
4.采用复制算法
ParNew (jdk1.4)
1.parNew是Serial的多线程版本,由多条GC线程并行进行垃圾回收,但清理过程仍然需要停止一切用户线程,但是速度更快。
2.适合多CPU环境。
3.与Serial相比,多CPU环境下性能会有一定的提升,但是切换线程需要有额外的开销,因此在单CPU环境中不如Serial
4.采用复制算法。
5.追求降低停顿时间,合交互式应用
Parallel Scavenge(jdk1.4)
1.Parallel Scavenge 和 ParNew一样都是多线程
2.复制算法进行垃圾回收
3.Parallel Scavenge追求CPU吞吐量,适合没有交互的计算机
2.老年代垃圾收集器
Serial Old(jdk1.3)
1.Serial Old收集器是Serial的老年代版本,都是单线程收集器
2.回收算法使用标记-整理法
Parallel Old(jdk1.6)
1.是Paraller Scavenge的老年代版本
2.一般搭配使用追求CPU吞吐量
CMS(jdk1.5)
1.CMS垃圾收集器是一款追求停顿时间的老年代收集器
2.他在垃圾收集的时候使用户线程和GC线程并行执行,因此垃圾收集过程中用户不会感受到明显的卡顿
3.存在切换线程的额外开销,消耗时间变长。
3.通用垃圾收集器
G1(jdk1.7)
1.追求停顿时间
2.多线程GC
3.面向服务端应用
4.标记-整理 和 复制算法 合并,不会产生碎片内存。
5.可对整个堆进行垃圾收集
6.可预测停顿时间。
G1的内存模型
G1垃圾收集器没有没有新生代和老年代的概念,而是将堆划分成为一块独立的Region
当进行垃圾收集时,首先估计每个Region的垃圾数量
每次都从垃圾回收价值最高的Region开始回收,因此可以获得最大回收效率。
回收价值由回收产生的空间和回收时间决定
JVM性能监控与故障分析
JDK的命令行工具
jps
虚拟机进程状况工具
命令格式
jps [option][hostid]
主要选项
-q 只输出LVMID,省略主类的名称
-m 输出虚拟机进程启动时传递给主类main()函数的参数
-l 输出主类的全名,如果进程执行的是jar包,输出jar路径
-v 输出虚拟机进程启动时JVM参数
jinfo
Java配置信息工具
jinfo [option] pid
-flag name 打印指定命令的名称和值
-flag [+|-]name 启用或禁用指定的布尔命令
-flag name=value 将指定的属性设置为指定的值
-flags 打印传递给JVM的非默认参数
-sysprops 打印Java系统属性
命令使用
jinfo -flag MaxHeapSize 41686
jinfo -flags 41686
jstat
虚拟机统计信息监视工具
1、查看类装载的信息
2、查看垃圾收集的信息
3、JIT编译的信息
jstat [option vmid [interval[s|ms] [count]]]
-class 监视类装载,卸载数量,总空间以及类装载、卸载总共所消耗的时间
-gc 监视Java堆状况,包括Eden区、两个survivor区,老年代,元空间等的容量、已用空间,GC时间合计等信息
1、S0C、S1C、S0U、S1U:S0和S1的总量和使用量
2、EC、EU:Eden区总量与使用量
3、OC、OU:Old区总量与使用量
4、MC、MU:Metaspace区总量与使用量
5、CCSC、CCSU:压缩类空间总量与使用量
6、YGC、YGCT:YoungGC的次数与时间
7、FGC、FGCT:FullGC的次数与时间
8、GCT:总的GC时间
-gccapacity 监视内容与-gc基本相同,但输出主要关注Java堆各个区域使用到的最大、最小空间
-gcutil 监视内容与-gc基本相同,但输出主要关注已使用空间占总空间的百分比
-gccause 与-gcutil功能一样,但是会额外输出导致上一次GC产生的原因
-gcnew 监视新生代GC状况
-gcnewcapacity 监视内容与-gcnew基本相同,输出主要关注使用到的最大,最小空间
-gcold 监视老年代GC状况
-gcoldcapacity 监视内容与-gcold基本相同,输出主要关注使用的最大,最小空间
-gcmetacapacity(-gcpercapacity jdk8之前使用的永久代) 输出元空间使用到的最大、最小空间
-compiler 输出JIT编译器编译过的方法、耗时等信息
-printcompilation 输出已经被JIT编译的方法
jmap,定位内存溢出
Java内存映像工具
jmap [option] vmid
-dump 生成Java堆转储快照
live:只导出存活对象,不指定导出全部
format=b:导出文件类型,二进制类型(binary forma)
file=<file>:导出到哪个文件
-finalizerinfo
显示在F-Queue中等待Finalizer线程执行finalize方法的对象
-heap 显示Java堆详细信息,如使用哪种回收器,参数设置,分代情况等
-histo 显示堆中对象统计信息,包括类、实例数量、合计容量
-F 当虚拟机进程对-dump选项没有响应时,可使用这个选项强制生成dump快照
定位内存溢出步骤
1、导出内存映像文件
方式一:内存溢出自动导出:-XX+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./
方式二:使用jmap命令手动导出
jhat
虚拟机堆转储快照分析工具
jstack
Java堆栈跟踪工具
HSDIS
JIT生成代码反汇编
BTrace
可视化工具
JVM性能调优
JVM参数级别
公司
默认JVM参数
已有工具
0 条评论
下一页