码迷,mamicode.com
首页 > 编程语言 > 详细

lesson2-java虚拟机之jvm结构

时间:2015-08-26 01:57:54      阅读:278      评论:0      收藏:0      [点我收藏+]

标签:虚拟机   内存管理   java   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虚拟机都能有一致的行为表现。

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

lesson2-java虚拟机之jvm结构

标签:虚拟机   内存管理   java   java开发工具   jvm   

原文地址:http://blog.csdn.net/lisaem/article/details/47988383

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!