JVM体系
2023-01-13 15:36:59 59 举报
AI智能生成
JVM体系
作者其他创作
大纲/内容
归类
Java虚拟机整体架构祥图
JAVA文件-->字节码文件-->JAVA虚拟机
JVM 的主要组成部分及其作用
类加载子系统:加载字节码文件到运行数据区的方法区
执行引擎:执行字节码文件中的指令
本地方法接口:java调用其他语言的接口,与本地资源交互
运行时数据区:JVM的内存
执行流程
首先通过编译器把 Java 代码转换成字节码,类加载器(ClassLoader)再把字节码加载到内存中,将其放在运行时数据区(Runtime data area)的方法区内,而字节码文件只是 JVM 的一套指令集规范,并不能直接交给底层操作系统去执行,因此需要特定的命令解析器执行引擎(Execution Engine),将字节码翻译成底层系统指令,再交由 CPU 去执行,而这个过程中需要调用其他语言的本地库接口(Native Interface)来实现整个程序的功能。
Java程序运行机制
java代码--编译器-->字节码文件--类加载器-->方法区
堆:java.lang.Class对象-->封装方法区内数据结构
Java代码执行过程详图
JAVA文件-->字节码文件-->JAVA虚拟机
汇编语言、机器语言、高级语言关系
JVM的架构模型
基于栈式
优点
设计和实现简单,适用于资源受限的系统
避开了寄存器的分配难题:使用零地址指令方式分配
指令流中大部分都是零地址指令,执行过程依赖操作栈,指令集更小,编译器容易实现
8位字节码,所以说指令集更小,但是完成一项操作花费的指令相对多。
不需要硬件支持,可移植性更好,更好实现跨平台
缺点
性能下降,实现同样的功能需要更多的指令,毕竟还要入栈出栈等操作
基于寄存器式
优点
性能优秀,执行更高效
花费更少的指令去完成一项操作
缺点
指令集架构完全依赖硬件,可移植性差
典型应用是X86的二进制指令集,比如传统的PC以及安卓的Davlik虚拟机
16位字节码
大部分情况下,指令集往往以一地址指令,二地址指令和三地址指令为主。
javap 查看字节码
-v输出附加信息
-l输出行号和本地变量表
-p显示所有类和成员
-c对代码进行反汇编
指令
地址、操作数
零地址只有操作数
基于栈式的,因为是操作栈顶的元素,所以不需要地址
一地址有一个地址,一个操作数
二地址有两个地址,一个操作数
JVM的生命周期
虚拟机的启动
通过引导类加载器bootstrap class loader创建一个初始类来完成的,这个类是由虚拟机的具体实现指定的。
虚拟机的执行
执行一个所谓的Java程序的时候,真正执行的是一个叫Java虚拟机的进程
虚拟机的退出
程序正常执行结束
执行过程遇到异常或错误而异常终止
操作系统错误导致Java虚拟机进程终止
Runtime类或System类的exit方法、runtime类的halt方法,并且Java安全管理器允许这次exit或halt操作
halt停止、停下、阻止
exit方法源码:static native void halt0(int status)
JNI(Java Native Interface)规范描述了用JNI Invocation API来加载或卸载Java虚拟机时,Java虚拟机退出的情况
JVM发展历程
sun Classic VM
世界第一款商用Java虚拟机
JDK1.4时被淘汰
只提供了解释器
如果使用JIT编译器,就需要外挂,但是JIT和解释器不能配合工作
Exact VM
为了解决上一个虚拟机问题,JDK1.2时,sun提供了此虚拟机
Exact Memory Management:准确式内存管理
虚拟机知道内存中某个位置的数据是什么类型
具有现代高性能虚拟机的雏形
热点探测
编译器与解释器混合工作模式
只在Solaris平台短暂使用,其他平台还是Classic vm
英雄气短,被hotspot虚拟机替换
hotspot虚拟机
最初由Longview Technologies的小公司设计,1997年被sun公司收购,2009年sun公司被甲骨文收购
JDK1.3时,HotSpot VM成为默认虚拟机
绝对市场地位,称霸武林
JDK6,8等均默认
HotSpot就是他的热点代码探测技术
通过计数器找到最具编译价值代码,触发即时编译或栈上替换
通过编译器与解释器协同工作,在优化响应时间和最佳执行性能中取得平衡
走路去目的地,
JRockit
BEA公司
专注服务器端应用
不太关注程序启动速度,引起JRockit内部不包括解析器实现,全部代码靠即时编译器编译后执行
世界上最快的JVM
全面的Java运行时解决方案组合
JRockit Real Time提供毫秒或微秒级的JVM响应时间,适合财务、军事指挥,电信网络的需要
MissionControl服务套件,极低的开销,来监控、管理和分析生成环境中的应用程序的工具
2008年BEA被oracle收购
JDK8中,在HOTSPOT的基础上,移植JRockit的优秀特性
IBM J9
全称:IBM Technology for java Virtual Machine 简称IT4J,内部代号J9
市场定位与HotSpot接近,服务器端、桌面应用,嵌入式等多用途VM
广泛应用于IBM的各种Java产品
IBM产品结合使用性能最好
有影响力的三大商用虚拟机之一
2017开源,OPEN J9
KVM和CDC/CLDC HotSpot
JavaME产品线产品
智能控制器、传感器、老人手机等
Azul VM
与特定硬件平台绑定、软硬件配合的专有虚拟机
运行于Azul Systems公司的专有硬件Vega系统上的虚拟机
每个实例可以管理至少数十个CPU和数百GB内存的硬件资源,并提供在巨大内存范围内实现可控的GC时间的垃圾收集器,专有硬件优化的线程调度等优秀特性
2010年,发布自己的Zing JVM,可以在通用X86平台上提供接近于vega系统的特性
Liquid VM
BEA公司开发的,运行在自家Hypervisor系统上
不需要操作系统支持,本身实现了一个专用操作系统的必要功能,如线程调度、文件系统、网络支持等
随着JRockit虚拟机终止开发,Liquid VM项目也停止了
Apache Harmony
JDK1.5,1.6兼容
IBM和Intel联合开发的开源JVM,2011年退役
Java类库代码吸纳进了Android SDK
Microsoft JVM
只能在Windows平台运行,xp系统中不用了。
TaobaoJVM
基于OpenJDK开发了自己的定制版本AlibabaJDK
深度定制且开源的高性能服务器版JAVA虚拟机
GCIH:GC invisible heap,将生命周期较长的Java对象从heap中已到heap之外,并且GC不能管理GCIH内部的Java对象,以此达到降低GC的回收频率和提升GC的回收效率
GCIH中的对象还能够在多个JAVA虚拟机进程中实现共享
使用crc32指令实现JVM intrinsic降低JNI的调用开销
针对大数据场景的ZenGC
在阿里产品上性能高,硬件严重依赖intel的CPU,损失了兼容性,但是提高了性能
淘宝、天猫上线,把oracle官方JVM版本全部替换
Dalvik VM
谷歌开发,应用于Android系统,安卓2.2提供了JIT,发展迅猛
只能称作虚拟机,不能称作Java虚拟机,没有遵循Java虚拟机规范
不能直接执行Java的Class文件
基于寄存器架构,不是jvm的栈架构
执行的是编译后的dex文件,执行效率比较高
安卓5.0使用支持提前编译AOT的ART VM替换Dalvik VM
Grall VM
2018年4月,Oracle labs公开了GraalVM。
跨语言全栈虚拟机,可以作为任何语言的运行平台使用
JVM调优工具
垃圾收集器
串行收集器(Serial收集器)
单线程的收集器,年轻代采用标记复制、老年代采用标记整理的算法,全程STW
并行收集器(Parallel Scavenge)
Serial收集器的多线程版本,可以根据-XX修改线程数量,非必要不修改,年轻代用的是标记复制算法,老年代用的是标记整理算法,收集全程STW
ParNew收集器
l逻辑与并行的Parallel收集器一样,区别在于可以和CMS配合使用,ParNew作用于年轻代,Parallel可以作用于年轻代与老年代
CMS收集器
初始标记
标记GCRoots元对象直接能引用的对象,短时间STW
并发标记
根据GCRoots所引用的对象,遍历整个对象图,整个过程时长较长,但是不会STW
重新标记
这个步骤是为了修复并发标记中,所产生变化的对象,主要是用的三色算法,会STW
并发清理
与用户线程同步进行,如果有新增的对象会被标记为黑色。采用的是标记清理算法
问题
无法处理浮动垃圾,只能留在下一次GC进行回收
会和服务抢占资源,对CPU资源比较敏感
利用的是标记清理算法,会有垃圾碎片,但是可以配置几次GC后执行一次标记整理
在这次fullGC没执行完成的清空下,又开始了下一次GC,这时CMS会转变为Serial收集器进行回收,全程STW单线程收集。
G1收集器
ZGC收集器
垃圾收集算法
标记清理
标记非垃圾对象,其余的全部回收,会产生大量空间碎片
标记整理
和标记清理前期算法一致,但是标记完成后不会直接清理,而是将存活对象已到一端移动,完成后将未移动的直接清理
标记复制
将内存分为两部分,其中一部分使用完成后,将存活的对象复制到空闲的一部分,另外一部分之前清理
内存分配机制
对象创建流程
类加载检查
分配内存空间
指针碰撞
空闲列表
初始化
设置对象头
哈希码
GC分代年龄
锁信息
元数据指针
为什么要进行指针压缩?
在64位平台的HotSpot中使用32位指针,内存使用会多出1.5倍左右,使用较大指针在主内存和缓存之间移动数据,占用较大宽带,同时GC也会承受较大压力
为了减少64位平台下内存的消耗,启用指针压缩功能
在jvm中,32位地址最大支持4G内存(2的32次方),可以通过对对象指针的压缩编码、解码方式进行优化,使得jvm 只用32位地址就可以支持更大的内存配置(小于等于32G)
init(属性赋值)
对象内存分配
入栈
逃逸分析
标量替换
进入Eden区
当Eden没有足够的空间时会触发一次MinorGC
Eden与Survivor的比例默认为8:1:1
进入老年代
大对象直接进入老年代
分代年龄达到进入老年代,每次Minior都会使年龄+1
对象动态年龄判断
当幸存者区域所有分带年龄大于0的对象总和超过了幸存区区域的百分之五十,这时会将这部分对象放到老年代中
老年代分配担保机制
在做minorGC之前会计算老年代剩余空间 是否大于年轻代所有对象总和,如果不是就会触发FULLGC
对象内存回收
可达性算法
根据静态变量,本地方法栈,线程栈本地变量等等作为GC Roots来搜索引用的对象,这部分对象标记为非垃圾对象
整体结构分析
类加载子系统
执行引擎
内存模型
堆
Eden区
幸存一区
幸存二区
老年代
栈
局部变量表
操作数栈
动态连接
方法出口
本地方法栈
主要是以C/C++语言实现的底层方法
元空间
常量
静态变量
类信息
程序计数器
类加载机制
双亲委派机制
加载某个类时,会先委托父加载器寻找目标类,如果没有找到,会再往上寻求上级加载类寻找,如果所有父加载类都找不到目标类,这时才会在自己的类加载路径中寻找并载入目标类
为什么会设计双亲委派机制
沙箱安全机制:防止JDK核心类库API被恶意篡改
避免类的重复加载
引导类加载器
扩展类加载器
应用程序加载器
自定义类加载器
重写findClass方法
loadClass方法实现了双亲委派机制
0 条评论
下一页