JVM的组成部分

本文详细解析了Java虚拟机(JVM)的内部结构,包括类加载器、执行引擎、本地接口、运行数据区等核心组件的功能与工作原理。同时,深入探讨了JVM的内存管理,涵盖栈、堆内存、方法区等关键概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们先把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 本地方法栈

<think>嗯,用户想了解JVM的主要组成部分。我之前回答过类似的问题,但需要结合用户提供的引用内容。引用[1]提到JVM由5部分组成,包括内存划分中的堆。引用[2]则补充了类加载器、字节码校验等运行机制。用户可能正在学习JVM架构或解决相关问题,比如内存溢出或类加载问题。 首先,我需要整理JVM的主要组件。通常,JVM分为类加载子系统、运行时数据区、执行引擎、本地方法接口和本地方法库。运行时数据区又包括堆、方法区、虚拟机栈、本地方法栈和程序计数器。但根据用户提供的引用,引用[1]提到5部分,其中堆是内存划分的一部分,而引用[2]强调了类加载过程和字节码校验。可能用户引用的资料分类方式不同,需要将两者结合起来。 要确保回答覆盖用户提到的内容,同时补充其他关键部分。比如,引用[1]中的堆是内存区域的一部分,而运行时数据区还包括其他部分。类加载子系统对应引用[2]中的类加载器。执行引擎和本地方法接口可能没有被引用提到,但它们是标准组成部分,需要包括进去。 另外,用户可能关心这些组件如何协同工作。比如类加载器加载类后,数据存储在运行时数据区,执行引擎处理字节码。同时,垃圾回收发生在堆内存,这也是性能调优的重点。 需要检查是否有遗漏的部分,比如JIT编译器属于执行引擎的一部分。还要注意引用中的“字节码校验”属于类加载过程中的验证阶段,应归类到类加载子系统中。 最后,生成相关问题时,要考虑用户可能的后续需求,如内存管理、类加载机制、垃圾回收算法等。确保问题能引导用户深入学习各个组件。</think>### JVM的主要组成部分解析 JVMJava虚拟机)的架构设计包含以下核心组件,这些组件协同工作以实现Java程序的跨平台运行和高效管理: --- #### 1. **类加载子系统(Class Loader Subsystem)** 负责加载字节码文件(`.class`)到内存中,包含三个阶段: - **加载**:查找并读取类文件。 - **链接**:验证字节码合法性(*字节码校验*[^2])、为静态变量分配内存、解析符号引用。 - **初始化**:执行静态代码块和变量赋值。 类加载器分为: - 启动类加载器(Bootstrap Class Loader) - 扩展类加载器(Extension Class Loader) - 应用程序类加载器(Application Class Loader) - 自定义类加载器(用户定义) --- #### 2. **运行时数据区(Runtime Data Areas)** JVM内存的核心划分[^1],包括: - **堆(Heap)**:存储对象实例和数组,是垃圾回收的主要区域。 - **方法区(Method Area)**:存储类结构(如常量池、字段、方法代码)。 - **虚拟机栈(JVM Stack)**:保存方法调用栈帧(局部变量、操作数栈)。 - **本地方法栈(Native Method Stack)**:支持Native方法(如C/C++代码)。 - **程序计数器(Program Counter Register)**:记录当前线程执行位置。 --- #### 3. **执行引擎(Execution Engine)** 负责解释或编译字节码为机器指令: - **解释器**:逐行解释执行字节码。 - **即时编译器(JIT Compiler)**:将热点代码编译为本地机器码。 - **垃圾回收器(GC)**:自动回收堆内存中的无效对象。 --- #### 4. **本地方法接口(JNI, Java Native Interface)** 提供Java调用操作系统本地方法(如C/C++库)的桥梁。 --- #### 5. **本地方法库(Native Libraries)** 包含操作系统或第三方提供的本地库文件,通过JNI调用。 --- ### 组件协同示例 1. 程序启动时,**类加载器**加载`Main.class`到方法区。 2. **执行引擎**解释`main()`方法的字节码,在虚拟机栈中创建栈帧。 3. 创建对象时,对象实例存储在**堆**中。 4. **垃圾回收器**定期清理无引用的对象释放内存。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值