深入理解JVM

来源:互联网 发布:php 检验日期格式 编辑:程序博客网 时间:2024/06/05 04:52

   本文转载自:http://www.qszxin.com/notes/53.html

   前面两篇关于Java的文章简单介绍了JavaJREJVM之间的联系以及JVM的一些特点,我们都知道Java字节码运行在JRE(Java Runtime Environment)中,而JRE中最重要的就是Java Virtual Machine(JVM)了,JVM负责解释和执行Java字节码,从Java程序员的角度来看,我们并不需要了解JVM如何运行就可以写出很多漂亮的程序。

   但是作为一名Java开发者,如果能够深入理解JVM的工作原理,可以帮助我们对Java这门语言有着更加深刻的认识,提高真实水平,也可以解决一些看上去摸不着头脑的bug,让程序更加具有效率。所以,这篇文章里,我将深入介绍JVM的工作原理,JVM的体系结构。

    对于JVM的特点介绍请看我之前写的文章JVM初步了解,这里深入介绍JVM的结构,下图是Java程序的执行流程:

 

 

中间绿色部分就是JVM的结构,一个类加载器加载Java字节码到运行时数据区,执行引擎执行Java字节码,指令计数器指向当前应该执行的指令。

运行时数据区详细结构图如下:

 

从操作系统的角度来看,进程是资源分配的最小单位,而线程则是CPU管理、调度的最小单位,线程往往共享所属进程的内存资源,但是线程的运行也需要分配一些资源,比如计数器、栈。当Java程序在JVM运行时,JVM就会为该进程分配数据区,进程运行时,每创建一个线程,都会为线程分配计数器、JVM栈、本地方法栈。

单个线程的数据区:

l 程序计数器:线程启动的时候,计数器就会被创建,其记录当前需要执行的指令地址

l JVM栈:线程启动的时候,栈就会被创建,栈中存储的是栈帧(Stack Frame),这里的栈也就是我们数据结构讲的栈,可以进行PushPop操作栈帧。结构图如下:

                     

当一个方法在JVM中执行时,栈帧被创建,并且存储到对应线程的JVM栈中,当方法执行完毕返回时,从该线程的JVM栈中移除。因为在编译时就可以确定局部变量和操作数的大小,所以栈帧的大小也是确定的。

局部变量数组:索引0存储的是该方法所属对象的引用,从索引1开始存储的是方法参数,方法参数后存储的是方法内的局部变量。

操作数栈:这是方法的实际工作区,每个方法都是在操作数栈和局部变脸数组交换数据。我的理解是可以参考x86指令集,x86指令集中会使用一些通用寄存器来暂存中间数据,但是正如上篇文章所讲的JVM特点,JVM不是基于寄存器的,而是基于栈的。

l 本地方法栈:本地方法所需要的栈空间,JVM借助于JNI(Java Native Interface)执行C/C++程序,所以专门为这些程序创建栈空间。我的理解是,毕竟JVM是架构在真实操作系统之上,比如WindowsLinux之上,JVM也需要使用操作系统提供的接口来实现功能。

多线程共享的数据区:

l 堆:存储数组和对象,因为这一部分是动态存储的,垃圾回收会定时对该存储区进行回收空间

l 方法区:包括运行时常量池,类结构信息和方法信息,静态变量,每个类的方法字节码。

l 运行时常量池:每个类或者接口编译后的.class文件中具有常量池表,当JVM装载类之后,就解析常量池表到运行时常量池,其中包括数字值,String值,和运行时解析的方法引用(method reference)和属性域引用(field reference)。


0 0
原创粉丝点击