当前位置:网站首页>JVM内部结构图及各模块运行机制总结
JVM内部结构图及各模块运行机制总结
2022-08-03 01:37:00 【找找Bug】
1.JVM内部模型图

JVM执行流程:
利用前端编译器(javac)将.java文件编译为.class文件(字节码文件),然后通过类加载子系统将.class文件加载到运行时数据区,之后通过执行引擎对.class文件进行解释执行。
2 类加载子系统
类加载子系统有七个操作:加载、链接(验证、准备、解析)、初始化、使用、卸载
2.1 加载
把.class文件读取到运行时数据区中,详细步骤为:
(1)通过全限定名读取到该类的二进制流(即,.class文件);
(2)将该二进制流的静态结构读取到运行时数据区中的方法区中;
(3)在堆中创建该类的实例对象。
注意:加载时采用的是双亲委派机制,其原理如下图所示,当某个类加载器收到类加载请求时,会自底向上将此请求委派给其父类加载器,若最顶层的启动类加载器(Bootstrap ClassLoader)不能加载此类,则自上而下把请求交还给其子类加载器,途中有类加载器可以加载此类,则进行加载,否则一直往下传递。若到达最底层的自定义类加载器(若没有自定义类加载器,则就是应用程序类加载器(Application ClassLoader))仍无法加载此类,则报出异常。


2.2 链接
2.2.1 验证
验证字节码文件是否符合JVM规范,比如字节码文件的文件开头是“CA FE BA BE”(称为魔数),这标识了它是JVM的字节码文件。
2.2.2 准备
为静态变量(static修饰)分配内存并赋初始值。
2.2.3 解析
将常量池中的符号引用(如#1,#2可能代表某个类,某个方法的符号引用)变为直接引用(内存地址)。
2.3 初始化
将静态变量的赋值动作以及静态代码块(static{})发生的操作整合为clinit方法进行执行。其实就是为静态变量进行真正意义上的赋值。
2.4 使用
2.5 卸载
3 运行时数据区
3.1线程私有区域
Java虚拟机栈:
保存局部变量表、操作数栈、动态链接、方法出口;每个线程单独拥有一个,用于执行程序;栈中的以栈帧为一个单位,一个栈帧相当于一个方法;执行流程:当调用main方法时,会将main方法作为一个栈帧压入到栈顶,若在执行main方法时调用了其它方法,则会把其它方法也作为栈帧压入栈顶,当栈顶方法执行完毕就会弹出栈。若所有栈帧都弹出,则程序运行结束。
本地方法栈:
本地方法栈与Java虚拟机栈类似,但它是为了执行本地方法(Native Methods)。本地方法栈执行时,需要调用到本地方法接口(也叫JNI/Java Native Interface),而本地方法接口需要调用本地方法库。
程序计数器:
控制程序指令的执行顺序,程序该怎么执行,哪个方法先执行,哪个方法后执行。
3.2 线程共享区域
方法区:
保存类的信息、常量池、方法数据、方法代码、JIT代码缓存等等;方法区是一种逻辑上的概念(即,JVM规范),在JDK1.7及之前方法区的落地实现叫做永久代(PermGen space),它位于堆中。在JDK1.8永久代被移除,将其变为元空间(Metaspace)。元空间与永久代最大区别在于,元空间使用的是直接内存(本地内存),而永久代使用的是堆内存。
Java堆:
保存new出来的实例对象;
JDK1.6时字符串常量池在运行时常量池内,属于运行时常量池的一部分;
JDK1.6到JDK1.7的变化是把静态常量和字符串常量从方法区中移到了堆中;
JDK1.7到JDK1.8的变化是对方法区的实现由永久代变为了元空间。
即字符串常量池在JDK1.7之后就移到了堆中,且存储的是字符串对象的引用,而不是对象本身。
在JDK1.8版本中,Java堆划分为新生代(NewGen)和老生代(OldGen)。
新生代:
- 新生代由伊甸区(Eden space)、幸存from区(Survival from)、幸存to区(Survival to)构成。
- 新生代发生的GC是轻GC(Minor GC),使用的GC算法是复制算法,复制算法原理是:当触发Minor GC时,利用可达性分析算法将Eden区存活对象移到Survival to区域,同时也将Survival from区域的存活对象也移到Survival to区域,然后将Survival to区域存活对象都复制到Survival from区域,且清除那些失效对象。即,每次GC都是将存活对象存入到Survival to区域,然后将Survival from区域和Survival to区域调换位置(实际是对象的复制过程)来保证Survival to区域是空的。
- 复制算法适合存活周期较短的对象的垃圾回收,其优点是算法复杂度低,执行效率快,但内存空间浪费较大。
老生代:
- 老生代发生的是重GC(Full GC),使用的是标记清除和标记整理算法的混合版,当内存碎片产生较少时,使用标记清除算法。较多时,使用标记整理算法。
- 标记清楚算法:利用可达性分析算法标记存活对象(可达对象),然后统一删除不可达对象。共两次操作,执行效率较低,且可能会产生较多内存碎片,相比复制算法,内存浪费较少。
- 标记整理算法:利用可达性分析算法标记存活对象(可达对象),然后将它们移至一端,删除端以外的不可达对象。这样就可用保证内存的连续性,不会有内存碎片,内存使用率大幅提高,但是执行效率更低。
4 执行引擎
执行引擎由解释器、JIT编译器、垃圾回收器组成。
解释器:
用于程序代码的解释执行。
JIT编译器:
用于将热点代码(重复执行次数较多的代码)提前编译,存储在方法区中,以便下次使用。这是为了程序执行的效率考虑。
垃圾回收器:
新生代垃圾回收器:Serial、ParNew、Parallel Scavenge
老生代垃圾回收器:Serial Old、Parallel Old、CMS
边栏推荐
猜你喜欢

全栈---Proxy

南瓜科学新品上线 开辟益智玩具新世界

有趣简单的M2处理器性能实验:Swift与C代码执行速度的比较

粘包与拆包

FLIR E95 在8层楼看马路上行驶的CAR的热成像形态?

.NET in-depth analysis of the LINQ framework (four: IQueryable, IQueryProvider interface details)

Latex-查看预收录在arXiv.org上论文的TeX源文件

Violent recursion to dynamic programming 06 (the sword refers to Offer II 095. Longest common subsequence)

OpenWRT setup ipv6 network

孩子坐不住就是不专注?猿辅导揭秘专注力的三大误区
随机推荐
公司封装方式导出excel过程
Violence recursion to dynamic programming 08 (pony go chess)
项目管理到底管的是什么?
全栈----跨域
怎么从零编写一个 v3 版本的 chrome 浏览器插件实现 CSDN 博客网站的暗黑和明亮主题切换?
DJI内推码(2022年8月2日更新)
【Gopher 学个函数】边学边练,简单为 Go 上个分
【Flink】使用arthas在线诊断flink的那些事
List转Map的几种方式
13-security其他.md
【飞控开发高级教程2】疯壳·开源编队无人机-遥控整机代码走读、编译与烧写
优秀的 Verilog/FPGA开源项目总结及交流群
Introduction to agile development
Brute force recursion to dynamic programming 07 (516. Longest palindrome subsequence)
30岁测试开发年薪不足80万,还要被面试官diss混得太差?
visual studio 2012 为啥这么优秀
sql注入是什么意思以及防止sql注入?
个人开发者必备,免费 API 网关工具推荐
爆款视频怎么做?这里或许有答案
如何准备考pmp?