JVM的组成部分

我们先把JVM这个虚拟机画出来,如下图所示:
virtual虚拟机
Machine 机械
java Virtual Machine (java 虚拟机)
在这里插入图片描述
从这个图中可以看到,JVM是运行在操作系统之上的,它与硬件没有直接的交互。我们再来看下JVM有哪些组
成部分,如下图所示:在这里插入图片描述
该图参考了网上广为流传的JVM构成图,大家看这个图,整个JVM分为四部分:
q Class Loader 类加载器
类加载器的作用是加载类文件到内存,比如编写一个HelloWord.java程序,然后通过javac编译成class文件,
那怎么才能加载到内存中被执行呢?Class Loader承担的就是这个责任,那不可能随便建立一个.class文件就能

被加载的,Class Loader加载的class文件是有格式要求,在《JVM Specification》中式这样定义Class文件的
结构:
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
需要详细了解的话,可以仔细阅读《JVM Specification》的第四章“The class File Format”,这里不再详细说明。

友情提示:Class Loader只管加载,只要符合文件结构就加载,至于说能不能运行,则不是它负责的,那是
由Execution Engine负责的。
q Execution Engine 执行引擎
执行引擎也叫做解释器(Interpreter),负责解释命令,提交操作系统执行。
q Native Interface本地接口
本地接口的作用是融合不同的编程语言为Java所用,它的初衷是融合C/C++程序,Java诞生的时候是C/C++横
行的时候,要想立足,必须有一个聪明的、睿智的调用C/C++程序,于是就在内存中专门开辟了一块区域处理
标记为native的代码,它的具体做法是Native Method Stack中登记native方法,在Execution Engine执行时
加载native libraies。目前该方法使用的是越来越少了,除非是与硬件有关的应用,比如通过Java程序驱动打印
机,或者Java系统管理生产设备,在企业级应用中已经比较少见,因为现在的异构领域间的通信很发达,比如
可以使用Socket通信,也可以使用Web Service等等,不多做介绍。
q Runtime data area运行数据区
运行数据区是整个JVM的重点。我们所有写的程序都被加载到这里,之后才开始运行,Java生态系统如此的繁
荣,得益于该区域的优良自治,下一章节详细介绍之。
整个JVM框架由加载器加载文件,然后执行器在内存中处理数据,需要与异构系统交互是可以通过本地接口进
行,瞧,一个完整的系统诞生了!
2 JVM的内存管理
所有的数据和程序都是在运行数据区存放,它包括以下几部分:
q Stack 栈
栈也叫栈内存,是Java程序的运行区,是在线程创建时创建,它的生命期是跟随线程的生命期,线程结束栈内
存也就释放,对于栈来说不存在垃圾回收问题,只要线程一结束,该栈就Over。问题出来了:栈中存的是那些
数据呢?又什么是格式呢?
栈中的数据都是以栈帧(Stack Frame)的格式存在,栈帧是一个内存区块,是一个数据集,是一个有关方
法(Method)和运行期数据的数据集,当一个方法A被调用时就产生了一个栈帧F1,并被压入到栈中,A方法又
调用了B方法,于是产生栈帧F2也被压入栈,执行完毕后,先弹出F2栈帧,再弹出F1栈帧,遵循“先进后出”原则。
那栈帧中到底存在着什么数据呢?栈帧中主要保存3类数据:本地变量(Local Variables),包括输入参数和输
出参数以及方法内的变量;栈操作(Operand Stack),记录出栈、入栈的操作;栈帧数据(Frame Data),
包括类文件、方法等等。光说比较枯燥,我们画个图来理解一下Java栈,如下图所示:在这里插入图片描述
图示在一个栈中有两个栈帧,栈帧2是最先被调用的方法,先入栈,然后方法2又调用了方法1,栈帧1处于栈顶
的位置,栈帧2处于栈底,执行完毕后,依次弹出栈帧1和栈帧2,线程结束,栈释放。
q Heap 堆内存
一个JVM实例只存在一个堆类存,堆内存的大小是可以调节的。类加载器读取了类文件后,需要把类、方法、
常变量放到堆内存中,以方便执行器执行,堆内存分为三部分:
Permanent Space 永久存储区
永久存储区是一个常驻内存区域,用于存放JDK自身所携带的Class,Interface的元数据,也就是说它存储的是运
行环境必须的类信息,被装载进此区域的数据是不会被垃圾回收器回收掉的,关闭JVM才会释放此区域所占用
的内存。
Young Generation Space 新生区
新生区是类的诞生、成长、消亡的区域,一个类在这里产生,应用,最后被垃圾回收器收集,结束生命。新生
区又分为两部分:伊甸区(Eden space)和幸存者区(Survivor pace),所有的类都是在伊甸区被new出来
的。幸存区有两个: 0区(Survivor 0 space)和1区(Survivor 1 space)。当伊甸园的空间用完时,程序又
需要创建对象,JVM的垃圾回收器将对伊甸园区进行垃圾回收,将伊甸园区中的不再被其他对象所引用的对象
进行销毁。然后将伊甸园中的剩余对象移动到幸存0区。若幸存0区也满了,再对该区进行垃圾回收,然后移动
到1区。那如果1区也满了呢?再移动到养老区。
Tenure generation space养老区
养老区用于保存从新生区筛选出来的JAVA对象,一般池对象都在这个区域活跃。 三个区的示意图如下:在这里插入图片描述
q Method Area 方法区
方法区是被所有线程共享,该区域保存所有字段和方法字节码,以及一些特殊方法如构造函数,接口代码也在
此定义。
q PC Register 程序计数器
每个线程都有一个程序计数器,就是一个指针,指向方法区中的方法字节码,由执行引擎读取下一条指令。
q Native Method Stack 本地方法栈

猜你喜欢

转载自blog.csdn.net/qq_30443907/article/details/82979313