欢迎访问悦橙教程(wld5.com),关注java教程。悦橙教程  java问答|  每日更新
页面导航 : > > 文章正文

Java虚拟机JVM,虚拟机jvm

来源: javaer 分享于  点击 38953 次 点评:151

Java虚拟机JVM,虚拟机jvm


0.JDK(Java Development Kit), JRE(Java Runtime Environment), JVM(Java Virtual Machine)之间的关系:














1.Java虚拟机(JVM)的涵义:Java虚拟机是在一台真正的机器上用软件方式实现的假想机.

(1).抽象的Java虚拟机规范;

(2).具体的Java虚拟机实现;

(3).运行的Java虚拟机实例;


    JVM总是开始于一个main()方法,main()方法是程序的起点,它被执行的线程初始化为程序的初始线程,其他线程都由它来启动.Java中的线程分为两种:daemon(守护)和non-daemon(非守护),daemon线程是JVM自己使用的线程(如负责垃圾收集的线程).只要JVM中还有non-daemon线程在执行,就不会停止(强制退出,使用System.exit()方法).


2.体系结构:两种机制(类装载系统和运行引擎) + 内存区域(栈, 堆, 方法区, 程序计数器, 本地方法栈)

(1).类装载的原理和实现

    所谓装载,就是寻找一个类或接口的二进制形式,并用该二进制形式来构造代表这个类或接口的Class对象(Reflection机制)的过程,其中类或接口的名称是给定的(也可以通过计算得到).


    类装载的过程:

    (a).装载:查找或导入类或接口的二进制数据;

    (b).链接:

        i).校验:检查导入类或接口的二进制数据的正确性;

        ii).准备:给类的静态变量分配并初始化存储空间;

        iii).解析:将符号引用转成直接引用;

    (c).初始化:激活类的静态变量,初始化Java代码和静态Java代码块;


    类装载器要满足以下两个条件:

    (a).对于相同的类名,类装载器所返回的对象应该是同一个类对象;

    (b).Java中类的装载过程就是代理装载的过程;


    类装载器的分类:

    (a).Bootstrap装载器:从sun.boot.class.path装载运行时库的核心代码;

    (b).Extension装载器:继承Bootstrap装载器,从java.ext.dirs装载代码;

    (c).System Application装载器:从java.class.path(CLASSPATH环境变量)装载代码;

    (d).Applet装载器:从用户指定的网络上特定的目录装载应用程序代码;


    Java的类装载模型是一种代理(delegation)模型,当JVM要求类装载器ClassLoader装载一个类时,ClassLoader首先将这个类装载请求转发给它的父装载器.只有当父装载器没有装载并无法装载这个类时,ClassLoader才获得装载这个类的机会.这样,所有类装载器的代理关系就构成了一种树状关系,树根是类的根装载器,在JVM中以null表示.在创建一个装载器时,如果没有显式地给出父装载器,那么默认System Application装载器.


    所有的JVM都包括一个内置的类装载器,这个内置的类库装载器被称为Bootstrap装载器,它只能装载在设计时刻已知的类,因此JVM假定由Bootstrap装载器所装载的类都是安全的,可信任的,可以不经过安全认证而直接运行;当应用程序需要加载并不是设计时就知道的类时,必须使用用户自定义的装载器.


    Java中类的装载是由运行时系统组件ClassLoader和它的子类实现的:

    (a).loadClass()方法,入口点;

    (b).defineClass()方法,接收类文件的字节数组并把它转换成Class对象;

    (c).findSystemClass()方法,从本地文件系统装入文件(默认机制);

    (d).resolveClass()方法,解析装入的类,如果该类已经被解析,那么将不做处理;

    (e).findLoaderClass()方法,查看ClassLoader是否已经装入这个类;


(2).运行引擎

    JVM实现的核心,负责执行包含在已装载的类或接口中的指令.

    执行技术:解释执行,即时编译.

    指令集:JVM中一个方法的字节码流就是一个指令的序列.

    运行引擎取得下一条指令的三种方法:后面的指令,return等指令,异常处理指令.

    平台独立性,网络移动性,安全性左右了JVM指令集的设计.


(3).内存区域

    JVM的每个实例都有一个自己的方法域和堆,运行于JVM内的所有线程都共享这些区域;当JVM装载类文件的时候,它解析其中的二进制数据所包含的类信息,并把它们放到方法域中;当程序运行的时候,JVM把程序初始化的所有对象置于堆上,而每个线程创建的时候,都会拥有自己的程序计数器和栈,其中程序计数器中的值指向下一条即将被执行的指令,线程的栈则存储为该线程调用方法的状态;本地方法调用的状态被存储在本地方法栈,该方法栈依赖于具体的实现.

    JVM不使用寄存器保存计算的中间结果,而是用堆栈存放中间结果.


    (a).栈:当一个线程启动时,JVM会为它创建一个堆栈,堆栈用一些离散的frame类记录线程的状态.线程中正在执行的方法被称为当前方法,当前方法所对应的frame被成为当前帧.线程操作保存在帧中的数据时,它只操作当前帧的数据.当线程调用一个方法时,JVM生成一个新的帧,并压入线程的堆栈.所有保存在帧中的数据都只能被拥有它的线程访问,所以访问方法的本地变量时,不需要考虑多线程同步的栈帧.

    (b).本地栈帧:

        i).本地变量:在堆栈帧中被组织为一个从0计数的数组,指令通过提供它们的索引从本地变量区中取得相应的值.

        ii).操作数堆栈:被组织为一个以字为单位的数组,通过push和pop来实现访问.JVM是一个以堆栈为基础,而不是以寄存器为基础,指令主要是从操作数堆栈中取得需要的操作数.JVM将操作数堆栈视为工作区,很多指令通过先从操作数堆栈中pop值,在处理完以后再将结果push回操作数堆栈.

        iii).帧数据:保存常量池,方法返回值和异常分发需要的数据.

    (c).堆:JVM中只有一个堆,所有的线程共享.当程序创建一个类的实例或者数组时,都在堆中为新的对象分配内存.

        i).GC(Garbage Collection),垃圾收集是释放没有被引用的对象的主要方法,也可能为了减少堆的碎片而移动对象.

        ii).对象存储结构(Object Representation),每一个对象主要存储的是它的类和父类中定义的对象变量.当程序试图将一个对象转换为另一种类型时,JVM需要判断这种转换是否这个对象的类型,或者它的父类型(instanceof, 动态绑定).每一个JVM中的对象必须关联一个用于同步多线程的lock(mutex).同一时刻,只能有一个对象拥有这个对象的锁,除了实现对象的锁定,每一个对象还逻辑管理到一个"wait set"的实现.锁定帮助线程独立处理共享的数据,"wait set"帮助线程协作完成同一个目标.GC也需要堆中的对象是否被关联的信息.

        iii).数组的保存(Array Representation),在Java中,数组是一种完全意义上的对象.数组必须在堆中保存数组的长度,数组的数据和一些对象数组类型数据的引用.

    (d).方法区:程序中的所有线程共享一个方法区,所以访问方法区信息的方法必须是线程安全的.方法区也可以被GC收集(没有真正加载或"unreferenced"状态).方法区包含的信息:类型信息,常量池,域信息,方法信息,类的静态变量(所有对象共享一份拷贝),类的被声明为final的变量(所有对象共享一份拷贝),类加载器的引用,Class类的引用,方法列表(每一个被加载的非抽象类,JVM都会为它们产生一个方法列表以加快存取速度,这个列表保存这个类可能调用的所有实例方法的引用,包括那些父类中调用的方法).

    (e).程序计数器:每一个线程开始执行时都会创建一个程序计数器,只有一个字长(word),能够保存一个本地指针和返回值,总是指向该线程下一步要执行的指令.

    (f).本地方法栈:任何本地方法接口都使用某种形式的本地方法栈.


(4).GC:GC负责回收所有"不可达"对象的内存空间.

    Java Heap(堆)分为3个区:

    (a).Young,保存刚实例化的对象;

    (b).Old,当Young区被填满时,GC将对象移到Old区;

    (c).Permanent,保存Reflection对象,用于存放Class和Meta信息,Class在被Load的时候被放入该区域;GC不会对Permanent Space进行清理,如果Load很多Class,很可能出现Permanent Space错误.


    JVM有2个GC线程:第1个线程负责回收Heap的Young区,第2个线程在Heap不足时,遍历Heap,将Young区升级为Old区.

   

相关文章

    暂无相关文章
相关栏目:

用户点评