Java虚拟机(JVM)

来源:互联网 发布:鼠标宏编程怎么设置 编辑:程序博客网 时间:2024/05/22 04:25

java程序的执行过程

这里写图片描述
源文件(.java文件)经过java编译器编译(javac)之后,生成字节码文件(.class文件)。
java运行环境(JRE)中的类加载器(class loader)加载硬盘上的字节码文件(.class文件),载入到java虚拟机(JVM)的内存区域(由系统分配)——运行数据区域(runtime data areas)。执行引擎(execution engine)之后解释或者编译类文件,转化成特定CPU的机器码。之后CPU执行机器码,完成整个执行过程。

JVM

Java虚拟机(java virtual machine,JVM)是java的核心和基础,在java编译器和os平台之间的虚拟处理器。它是一种基于下层的操作系统和硬件平台并利用软件方法来实现的抽象的计算机,可以在上面执行java的字节码程序。
JVM是Java程序运行的容器,但是他同时也是操作系统的一个进程,因此他也有他自己的运行的生命周期,也有自己的代码和数据空间。
JVM由三部分组成:类加载器、运行数据区、执行引擎。

类加载器

类加载器用来加载经过编译后的字节码文件(class文件)到JVM的运行数据区。类加载器被组织成一种层级结构关系,也就是父子关系。其中Bootstrap是所有类加载器的父亲。
这里写图片描述

  • Bootstrap Class Loader
    当运行java虚拟机(java classFile命令)时,这个类加载器被创建,它加载一些基本的java API,包括Object这个类。需要注意的是,这个类加载器不是用java语言写的,而是用C/C++写的。

  • Extenxion Class Loader
    这个加载器加载出了基本API之外的一些拓展类,包括一些与安全性能相关的类。

  • System Class Loader
    它加载应用程序中的类,也就是在你的classpath中配置的类。

  • User-Defined Class Loader
    这是开发人员通过拓展ClassLoader类定义的自定义加载器,加载程序员定义的一些类。

类加载过程

  • 委派模式(delegation Mode)
    当JVM加载一个类时,首先自底向上检查该类是否已经加载。下层的类加载器会将加载任务委托给上一层类加载器,上一层加载检查它的命名空间中是否已经加载这个类,如果已经加载,直接使用这个类。如果没有加载,继续往上委托直到顶部。检查完了之后,按照相反的顺序进行加载,如果Bootstrap加载器找不到这个类,则往下委托,直到找到类文件。
    对于某个特定的类加载器来说,一个Java类只能被载入一次,也就是说在Java虚拟机中,类的完整标识是(classLoader,package,className)。一个类可以被不同的类加载器加载。

  • 可见性限制
    下层的加载器能够看到上层加载器中的类,反之则不行,也就是是说委托只能从下到上。

  • 不可卸载类

运行数据区

运行数据区(Runtime Data Areas):当运行一个JVM实例时,由系统为JVM分配一块内存区域(大小可以设定),并由JVM自己管理。在这块内存区域中,分出一块用来存储一些运行数据,例如创建的对象,传递给方法的参数,局部变量,返回值等等。分出来的这一块就称为运行数据区域。运行数据区域可以分为6块
这里写图片描述

  • PC寄存器(程序计数寄存器),PC Register
    每一个线程都拥有一个PC计数器,当线程启动(start)时,PC计数器被创建,这个计数器存放当前正在被执行的字节码指令(JVM指令)的地址。
  • Java栈,JVM Stack
    同样,java栈也是每个线程独自拥有,在线程启动时创建。这个栈中存放着一系列的栈帧(Stack Frame),JVM只能进行压入(push)和弹出(pop)栈帧两种操作。每当调用一个方法时,JVM就往栈里压入一个栈帧,方法结束返回时弹出栈帧。如果方法执行时出现异常,可以调用printStackTrace等方法来查看栈的情况。栈的示意图如下:
    这里写图片描述

java栈的组成有三部分:

1.局部(本地)变量数组
局部(本地)变量数组中,从0开始按顺序存放方法所属对象的引用、传递给方法的参数、局部变量。
例如:

public void fun(int a,double b,object o){...}

则这个方法的栈帧中局部变量数组的内容为

0:this1:a2,3:b4:o

其中double类型的b需要两个连续的索引。取值的时候,取出的是2这个索引中的值。如果是静态方法,则数组第0个不存放this引用,而是直接存储传递的参数。
2.操作数栈
操作数栈其实是一个数据临时存储区,存放一些中间变量,方法结束了,操作数栈也就没有了。
3.栈帧中数据引用

  • 本地方法栈,Native Method Stack

以上三个区域是每个线程独自拥有。
以下三个区域是所有线程共同拥有。

  • Java堆,Heap
    java堆为所有线程共享,堆中存放的是程序创建的对象和实例。堆区队JVM的影响很大,垃圾回收机制处理的就是这块内存区域。
  • 方法区域,Method Area
    方法区域是一个JVM实例中的所有线程共享的,当启动一个JVM实例时,方法区域被创建。它用于存放运行常量池、有关域和方法的信息、静态变量、类和方法的字节码。不同的JVM实现方式在实现方法区域的时候会有所区别。
  • 运行常量池,Runtime Constant Pool
    这个区域存放类和接口的常量,除此之外,它还存放方法和域的所有引用。当一个方法或者域被引用的时候,JVM就通过运行常量池中的这些引用来查找方法和域在内存中的的实际地址。

执行引擎

类加载器将字节码载入内存之后,执行引擎以Java 字节码指令为单元,读取Java字节码。通过解释器或者编译器将字节码转化成机器相关的机器码。

参考文章

0 0
原创粉丝点击