lesson2-java虚拟机之jvm结构



网上找了一大圈,对于java虚拟机,还是不清不楚。这张算是比较靠谱的图了。自己参考Java虚拟机规范 Java SE7版,研究了下java虚拟机的结构,浅显理解吧。下面根据这个图,理解下各个部分。

以上是JAVA虚拟机的结构图,这张图对应了很多jvm机制,比如java的类加载和执行机制,比如java的垃圾回收机制。本文专注于java虚拟机的结构。

在了解java虚拟机的结构之前,我们先大概了解下java虚拟机中可以操作的数据类型。

与java语言类似,jvm可以操作的数据类型可以分为两类:原始类型(primitive type,也常被称为原生类型,基本类型)和引用类型(reference type)。jvm希望尽可能多的类型检查能在程序运行之前完成,即编译器应当在编译期间尽最大努力,完成可能的类型检查,使得虚拟机在运行期间无需进行这些操作。

原始数据类型包括数值类型,boolean类型和returnAddress类型。其中数值类型包括整数类型和浮点类型。

整型有byte,short,int,long,均为有符号二进制补码,默认都为0,char型为16位无符号整数表示,指向基本多文种平面的Unicode码点,以UTF-16编码,默认为Unicode的null码点(\u0000)。

boolean类型为true和false,默认是false。boolean类型的数值,在编译之后,都使用jvm中的int数据类型来代替。jvm会将true映射为1,false映射为0。

returnAddress类型表示一条字节码指令的操作码,在虚拟机支持的所有原始类型中,只有该类型不能直接与java语言的数据类型对应。

浮点类型值得强调的一点是,该类型包含5个特殊数值,正数零,负数零,正无穷大,负无穷大,NaN。在浮点数中,整数0和负数0是相等的,但1.0/0.0会产生正无穷大结果,1.0/-0.0会产生负无穷大结果。NaN是无序的,对它进行任何的数值比较和等值测试,都会返回false。任何数字和NaN进行非等值比较都会返回true,除了其本身以外。

引用数据类型包括,类类型,数组类型,接口类型,默认值是null。在引用类型中有一个特殊的值,null。当一个引用不指向任何对象的时候,它的值就是null,在没有上下文的情况下不具备任何实际的类型,但在有上下文时,其可转换为任意的引用类型。

以上是针对虚拟机的数据类型的简要介绍。下面是运行时数据区的解释。

1.PC寄存器

jvm可以支持多条线程同时执行,每一条jvm线程都有自己私有的pc寄存器。在任意的时刻,一条jvm线程只会执行一个方法的代码,这个正在被执行的方法称为该线程的当前方法,如果这个方法不是native的,那么pc寄存器就保存jvm正在执行的字节码指令的地址,如果该方法是native的,那么pc寄存器的值是undefined。pc寄存器的容量至少应当能保存一个returnAddress类型的数据或者一个与平台相关的本地指针的值。

2.Java栈

每一个jvm线程都有自己私有的java虚拟机栈,这个栈和线程同时创建,用于存储栈帧。与传统语言的栈类似,存储局部变量以及中间过程。此外,java栈在方法调用和返回中也扮演了重要角色,因为除了栈帧的出栈和入栈以外,Java栈不再受其他因素的影响,所以栈帧可以在堆中分配,java栈所使用的内存不需要保证是连续的。java栈可以被实现成固定大小的或者是根据计算可动态扩展和收缩的。如果采用固定大小的,那么这个容量应该在jvm线程创建的时候确定。java虚拟机栈发生异常的情况有如下两种:1.线程请求分配的栈容量超过java栈的最大容量,此时会跑出StackOverflowError。2.如果是动态扩展的并且已经尝试过去获取更大的栈空间,但是无法申请到足够的内存去完成扩展,或者在创建新线程时没有足够的内存去创建对应的虚拟机栈,此时会跑出OutOfMemoryError。

3.java堆

java堆是所有jvm线程共享的运行时内存区,也是所有类实例和数组对象分配内存的区域。java堆在虚拟机启动的时候被创建,它存储了被自动内存管理系统(垃圾收集器)所管理的各种对象,这些受管理的对象无需也无法被显示地销毁。java堆的容量可以是固定大小,也可以是程序执行时动态扩展,并在不需要过多空间时自动收缩。java堆所使用的内存不需要保证是连续的。java堆发生异常的情况是,当实际所需的内存超过了自动内存管理系统所能提供的最大容量时,java虚拟机会抛出一个OutOfMemoryError异常。

4.方法区

在java虚拟机中,方法区是可供各个线程共享的运行时内存区。方法区和传统语言中的编译代码存储区或者操作系统的正文段的作用类似,它存储了每一个类的结构信息,例如运行时常量池,字段和方法数据,构造函数和普通方法的字节码,还包括一些类,实例,接口初始化时用到的特殊方法。(特殊方法后面会补充解释)。方法区在虚拟机启动的时候创建,它的容量可以是固定大小,也可以是程序执行时动态扩展,并在不需要过多空间时自动收缩。方法区在实际内存空间中可以是不连续的。如果方法区的内存空间不能满足内存分配请求,java虚拟机将抛出一个OutOfMemoryError异常。运行时常量池是class文件中每一个类或接口的常量池表的运行时表示形式(常量池表后面会补充解释)。它包括了若干种不同的常量,从编译期可知的数值字面量到必须运行期解析后才能获得的方法或字段的引用。每一个运行时常量池都在虚拟机的方法区中分配。在加载类和接口到虚拟机后,就创建了对应的运行时常量池。会抛出OutOfMemoryError异常。

5.本地方法栈

java虚拟机可能会用到传统的栈(C stack)来支持本地方法,即java语言以外的其他语言编写的方法。这个栈就是本地方法栈。当java虚拟机使用其他语言来实现指令集解释时,也会使用到本地方法栈。如果jvm不支持本地方法,并且自己也不依赖于传统栈,可以无需支持本地方法栈,如果支持,该栈一般在线程创建的时候按线程分配。本地方法栈可以被实现成固定大小的或者是根据计算可动态扩展和收缩的。如果采用固定大小的,那么这个容量应该在jvm线程创建的时候确定。发生异常的情况有如下两种:1.线程请求分配的栈容量超过栈的最大容量,此时会跑出StackOverflowError。2.如果是动态扩展的并且已经尝试过去获取更大的栈空间,但是无法申请到足够的内存去完成扩展,或者在创建新线程时没有足够的内存去创建对应的本地方法栈,此时会跑出OutOfMemoryError。以上是关于运行时数据区的分类解释。下面对刚刚提到的一些概念进行解释。

6.栈帧

栈帧是用来存储数据和部分过程结果的数据结构,同时也用来处理动态链接,方法返回值和异常分派。栈帧随着方法的调用而创建,随着方法的结束而销毁,无论方法是正常完成还是异常完成,都算作方法结束。栈帧的存储空间分配在java虚拟机栈之中,每一个栈帧都有自己的本地变量表,操作数栈,和指向改方法所属类的运行时常量池的引用。本地变量表和操作数栈的容量,在编译期确定,并通过方法的code属性保存并提供给栈帧使用,code属性在后面会介绍到。当前栈帧,当前方法,当前类概念略过。如果当前方法调用了其他方法,或者当前方法执行结束,那么这个栈帧就不再是当前栈帧。栈帧是线程本地私有的数据,不可能在一个栈帧之中引用另外一个线程的栈帧。

7.特殊方法

在java虚拟机层面上,java编程语言中的构造器是以一个名为init的特殊实例初始化的形式出现的。init这个方法的名称是由编译期命名的,因为它并非一个合法的java方法名,不可能通过程序编码实现。实例初始化方法只能在实例初始化期间,通过java虚拟机的invokespecial指令调用,只有在实例正在构造时,实例初始化方法才可以访问。一个类或者接口最多可以包含不超过一个类或者接口的初始化方法,类或者接口就是通过这个方法完成初始化的。这个方法是一个不包含参数的,返回类型为void的方法,名为clinit。

8.异常抛出

抛出异常的操作是java虚拟机中精确定义的程序控制权转移的操作。由java虚拟机执行的每个方法都会配有零个至多个异常处理器,异常处理器描述了其在方法代码中的有效作用范围,能处理的异常类型以及处理异常的代码所在的位置。要判断某个异常处理器是否可以处理某个具体的异常,需要同时检查异常出现的位置是否在异常处理的有效作用范围内,并且出现的异常是否是异常处理器声明的异常处理类型或者其子类型。当抛出异常时,java虚拟机搜索当前方法包含的各个异常处理器,如果能找到,则将代码控制权转移到异常处理器中描述的处理异常的分支中。

如果没有找到,并且当前方法调用期间确实发生了异常,那么当前方法操作的本地变量表,操作数栈都将被抛弃,随后它对应的栈帧出栈,线程的方法栈恢复到该方法调用者的栈帧中。未被处理的异常将在该方法的调用者栈帧中重新被抛出,并在整个方法调用链中不断地重复前面描述的处理过程,如果直到该方法调用栈的顶端,都没有找到合适的异常处理,那整个执行线程都将被终止。搜索异常处理器的顺序是很关键的, 在class文件中,每个方法的异常处理器都存在一张表中,运行时,当有异常抛出之后,java虚拟机会按照class文件中的异常处理器表描述的异常处理器顺序去搜索。需要注意的是,java虚拟机本身不会对异常处理器顺序进行排序,所以java语言中对异常处理的语义,实际上是通过编译器适当安排异常处理器在表中的顺序来协助完成的。只有在class文件中明确定义了异常处理器查找顺序,才能保证无论class文件通过何种途径产生,java虚拟机都能有一致的行为表现。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-12-21 10:15:22

lesson2-java虚拟机之jvm结构的相关文章

深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)PDF下载

网盘下载地址:深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)PDF下载 – 易分享电子书PDF资源网 作者: 周志明 出版社: 机械工业出版社 副标题: JVM高级特性与最佳实践 出版年: 2013-9-1 页数: 433 定价: 79.00元 装帧: 平装 内容简介 · · · · · · <深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)>内容简介:第1版两年内印刷近10次,4家网上书店的评论近4?000条,98%以上的评论全部为5星级的好评,是整个Java图书领域公

[转帖]Java虚拟机(JVM)体系结构概述及各种性能参数优化总结

Java虚拟机(JVM)体系结构概述及各种性能参数优化总结 2014年09月11日 23:05:27 zhongwen7710 阅读数 1437 标签: JVM调优jvm 更多 个人分类: Java知识点总结技术架构原理 https://blog.csdn.net/zhongwen7710/article/details/39213377 写的很好.. 堆栈分不清楚的我 愧对计算机系毕业.. 第一部分:相关的概念 数据类型 Java虚拟机中,数据类型可以分为两类:基本类型和引用类型.基本类型的变

Java虚拟机(JVM)中的内存设置详解

在一些规模稍大的应用中,Java虚拟机(JVM)的内存设置尤为重要,想在项目中取得好的效率,GC(垃圾回收)的设置是第一步. PermGen space:全称是Permanent Generation space.就是说是永久保存的区域,用于存放Class和Meta信息,Class在被Load的时候被放入该区域Heap space:存放Instance. GC(Garbage Collection)应该不会对PermGen space进行清理,所以如果你的APP会LOAD很多CLASS的话,就很

Java虚拟机笔记 – JVM 自定义的类加载器的实现和使用2

1.用户自定义的类加载器: 要创建用户自己的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的findClass(String name)方法即可,该方法根据参数指定类的名字,返回对应的Class对象的引用. findClass protected Class<?> findClass(String name) throws ClassNotFoundException 使用指定的二进制名称查找类.此方法应该被类加载器的实现重写,该实现按照委托模型来加载类.在通过父

Java虚拟机笔记 – JVM 自定义的类加载器的实现和使用

1.用户自定义的类加载器: 要创建用户自己的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的findClass(String name)方法即可,该方法根据参数指定类的名字,返回对应的Class对象的引用. findClass protected Class<?> findClass(String name) throws ClassNotFoundException 使用指定的二进制名称查找类.此方法应该被类加载器的实现重写,该实现按照委托模型来加载类.在通过父

深入理解Java虚拟机(jvm性能调优+内存模型+虚拟机原理)视频教程

14套java精品高级架构课,缓存架构,深入Jvm虚拟机,全文检索Elasticsearch,Dubbo分布式Restful 服务,并发原理编程,SpringBoot,SpringCloud,RocketMQ中间件,Mysql分布式集群,服务架构,运 维架构视频教程 14套精品课程介绍: 1.14套精 品是最新整理的课程,都是当下最火的技术,最火的课程,也是全网课程的精品: 2.14套资 源包含:全套完整高清视频.完整源码.配套文档: 3.知识也 是需要投资的,有投入才会有产出(保证投入产出比是

详细介绍Java虚拟机(JVM)

1. JVM生命周期 启动.启动一个Java程序时,一个JVM实例就产生了,任何一个拥有public static void main(String[] args)函数的class都可以作为JVM实例运行的起点. 运行.main()作为该程序初始线程的起点,任何其他线程均由该线程启动. 消亡.当程序中的所有非守护线程都终止时,JVM才退出:若安全管理器允许,程序也可以使用Runtime类或者System.exit()来退出. 一个运行中的Java虚拟机有着一个清晰的任务:执行Java程序.程序开

Java核心知识点-JVM结构之常量池

触摸java常量池 java常量池是一个经久不衰的话题,也是面试官的最爱,题目花样百出,小菜早就对常量池有所耳闻,这次好好总结一下. 理论 小菜先拙劣的表达一下jvm虚拟内存分布: 程序计数器是jvm执行程序的流水线,存放一些跳转指令,这个太高深,小菜不懂. 本地方法栈是jvm调用操作系统方法所使用的栈. 虚拟机栈是jvm执行java代码所使用的栈. 方法区存放了一些常量.静态变量.类信息等,可以理解成class文件在内存中的存放位置. 虚拟机堆是jvm执行java代码所使用的堆. Java中的

Java虚拟机(JVM)体系结构概述及各种性能参数优化总结

转自:http://blog.csdn.net/zhongwen7710/article/details/39213377 第一部分:相关的概念 数据类型 Java虚拟机中,数据类型可以分为两类:基本类型和引用类型.基本类型的变量保存原始值,即:他代表的值就是数值本身:而引用类型的变量保存引用值.“引用值”代表了某个对象的引用,而不是对象本身,对象本身存放在这个引用值所表示的地址的位置. 基本类型包括:byte,short,int,long,char,float,double,Boolean,r