java运行原理简介

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAeG1oLXN4aC0xMzE0,size_20,color_FFFFFF,t_70,g_se,x_16一、Java 运行原理 

 

1、高级语言运行过程 

在程序真正运行在CPU上之前,必须要让OS的kernel理解我们在编辑器或者IDE里根据每种语言的语法规则敲入的源代码,kernel才能做出相关的调度,所以需要先将源代码转化成可执行的二进制文件,这个过程通常由编译器完成。有些编译器直接将源代码编译成机器码,载入内存后CPU可以直接运行。而机器码的格式与跟具体的CPU架构相关连,例如ARM CPU无法理解Intel CPU机器码。因此,同样的源代码需要根据不同的硬件进行特定的编译。高级语言转换到低级语言的桥梁就是编译器。程序员写好源代码,编译器将源码编译成可执行的机码,然后CPU读取机器码,执行程序。 

2、Java语言的执行过程 

Java技术原理详解_java工作原理、java原理 

宽泛地讲,Java源代码(.java)经过java编译器(javac.exe)编译之后,并没有直接转化为机器码,而是转化成一种中间格式——字节码(.class),字节码再经过Java虚拟机解释,转化成机器码,然后经由操作系统到达CPU运行。整个执行过程如下图所示: 

Java技术原理详解_java工作原理、java原理_02 

Java的跨平台是基于JVM虚拟机这一中间物来实现的,Java源程序经过编译器编译后生成虚拟机能够理解的字节码(ByteCode——class文件的内容),虚拟机将每一条要执行的字节码送给解释器,解释器将其翻译成特定系统上的机器码,然后在特定的机器上运行。每一种平台的解释器是不同的,但是实现的虚拟机是相同的。 

Java技术原理详解_java工作原理、java原理_03 

3、JVM——Java Virtual Machine 

JVM是一个虚构出来的计算机,通过在实际的计算机上仿真模拟各种计算机功能来实现的。JVM有自己完善的硬件架构,如处理器、堆栈、寄存器等,还具有相应的指令系统。JVM 的主要工作是解释自己的指令集(即字节码)并映射到本地的 CPU 的指令集或 OS 的系统调用。 

三、 JVM的体系结构 

Class Loader:类装载器,从入口处开始按需加载.class文件,填充这些数据到运行时数据区 

Execution Engine:执行引擎,JVM的CPU,不断地取指令,JIT编译翻译执行字节码,或者执行本地方法 

Runtime Data Areas:运行时数据区,核心区,运行的时候操作所分配的内存区,包括方法区、堆、java栈、PC寄存器、本地方法栈 

Java技术原理详解_java工作原理、java原理_04 

1、类加载器 

类加载器加载其实就是根据编译后的Class文件,将Java字节码载入JVM内存,并完成对运行数据处于的初始化工作,供执行引擎执行。 

类加载过程: 

装载——链接(验证,准备,解析)—— 初始化 

Java技术原理详解_java工作原理、java原理_05 

1.Loading:,找到二进制字节码(Class文件)并加载至JVM内存中,标识一个被加载的类:类名+类所在的包名+Class Loader instance ID 

2.Linking:

 

Verifying:验证元数据,文件格式,字节码等,确保class文件包含的字节码信息符合JVM的规范,以免危及JVM安全;

 

Preparing:准备分配给类所需要内存的数据结构,指示在类中定义的字段、方法和接口;

 

Resolving:对类中的所有属性、方法进行验证,以确保其需要调用的属性、方法存在,以及具备应的权限;符号引用的转换等

 

3.Initialing:初始化执行类中的静态初始化代码、构造器代码以及静态属性 

类装载器类型: 

启动类装载器:JVM实现的一部分; 

用户自定义类装载器:是Java程序的一部分,必须是ClassLoader类的子类。 

类装载顺序: 

Jvm启动时,由Bootstrap向User-Defined方向加载类;应用进行Class Loader时,由User-Defined向Bootstrap方向查找并加载类; 

类加载采用父类委托制,子加载器能查询父加载器已缓存类,委托只能从下到上,反之不行。类加载器可以加载一个类,但是它不能卸载一个类。但是类加载器可以被删除或者被创建。一个类可以被不同的类加载器加载。 

Java技术原理详解_java工作原理、java原理_06 

Bootstrap ClassLoader 

JVM的根ClassLoader,它是用C++实现的,在JVM启动的时候创建,负责装载$JAVA_HOME中jre/lib/rt.jar(Sun JDK的实现)中所有class文件,这个jar中包含了Java规范定义的所有接口以及实现。 

Extension ClassLoader 

装载除了基本的Java API以外的扩展类,它也负责装载其他的安全扩展功能。 

System ClassLoader 

负责加载应用程序类,加载启动参数中指定的Classpath中的jar包以及目录,在Sun JDK中ClassLoader对应的类名为AppClassLoader。 

User-Defined ClassLoader 

Java开发人员继承ClassLoader抽象类自行实现的ClassLoader,基于自定义的ClassLoader可用于加载非Classpath中的jar以及目录。 

2、执行引擎 

类加载器将.class文件载入内存之后,执行引擎以Java 字节码指令为单元,读取Java字节码;而后由解释器或者即时编译器(JIT Compiler)将字节码转化成平台相关的机器码。 

Java技术原理详解_java工作原理、java原理_07

JVM实现技术: 

解释器:第一代JVM,一条一条地读取,解释并且执行字节码指令。因为它一条一条地解释和执行指令,所以它可以很快地解释字节码,但是执行起来会比较慢。这是解释执行的语言的一个缺点。字节码这种“语言”基本来说是解释执行的。 

Java技术原理详解_java工作原理、java原理_08 

即时编译器(just-in-time compiler):第二代JVM,狭义来说是当某段代码即将第一次被执行时进行编译,将class类文件解释成二进制文件后的结果缓存下来,当第二次执行时直接从缓存中取,因此JIT依赖更多内存缓存解释的结果。JIT编译是动态编译的一种特例。JIT编译一词后来被泛化,时常与动态编译等价;但要注意宽泛与狭义的JIT编译所指的区别。 

Java技术原理详解_java工作原理、java原理_09 

自适应编译器(adaptive compiler):柔和第一代和第二代JVM,也是动态编译的一种,但它通常执行的时机比JIT编译迟,先让程序“以某种形式”先运行起来,收集一些信息之后再做动态编译,也就是说在所有执行过的代码里只寻找一部分来编译;而”收集信息”决定了编译哪部分代码,换个角度说“收集信息”就是在程序运行过程中监控代码执行的频率,自动缓存利用率高的代码,这样的编译可以更加优化。这个”某种形式”可以称为“baseline execution“,可以由解释器或简单的JIT编译器承担。 

Java技术原理详解_java工作原理、java原理_10 

HotSpot是一个JVM的实现,得名于它得混合模式执行引擎(包括解释器和自适应编译器),这个JVM最初由Longview/Animorphic实现,随着公司被Sun/JavaSoft收购而成为Sun的JVM,并于JDK 1.3.0开始成为Sun的Java SE的主要JVM。在Sun被Oracle收购后,现在HotSpot VM是Oracle的Java SE的主要JVM。HotSpot是较新的JVM,用来代替JIT(Just in Time), Java原先是把源代码编译为字节码在虚拟机执行,这样执行速度较慢;而HotSpot将最需要编译的“热点”代码编译为本地(原生native)代码,如果已经被编译成本地代码的字节码不再被频繁调用了,那么Hotspot VM会把编译过的本地代码从cache里移除,并且重新按照解释的方式来执行它,这样显着提高了性能。 HotSpot VM 参数可以分为规则参数(standard options)和非规则参数(non-standard options)。Hotspot VM分为Server VM和Client VM两种,这两种VM使用不同的JIT编译器。 

3、运行时数据区 

当运行一个JVM Instance时,系统将分配给它一块内存区域(大小可设置),这一内存区域由JVM自行管理。从这一块内存中分出一块用来存储一些运行数据,例如创建的对象,传递给方法的参数,局部变量,返回值等等。这一块内存就称为运行数据区域。运行数据区域可以划分为6大块:Java栈、程序计数寄存器(PC寄存器)、本地方法栈(Native Method Stack)、Java堆、方法区域(包括运行常量池——Runtime Constant Pool)。其中每个线程私有程序计数器,JVM栈,本地方法栈,方法区和堆则由JVM实例中的所有线程共享,在同一个实例中可以启用多个线程。 

Java技术原理详解_java工作原理、java原理_11 

程序计数器 

每个线程私有,线程启动时创建,用来存放当前正在被执行的字节码指令(JVM指令)的地址,如该方法为native的,则PC寄存器中不存储任何信息。 

JVM栈 

每个线程私有,线程启动时创建。存放着一系列的栈帧(Stack Frame),JVM只能进行压入(push)和弹出(pop)栈帧这两种操作。每当调用一个方法时,JVM就往栈里压入一个栈帧,方法结束返回时弹出栈帧。如果方法执行时出现异常,可用printStackTrace等方法来查看栈的情况。栈的示意图如下: 

Java技术原理详解_java工作原理、java原理_12 

每个栈帧包含三个部分:本地变量数组,操作数栈,方法所属类的常量池引用

 

Local Variable Array:从0开始按顺序存放方法所属对象的引用、传递给方法的参数、局部变量。

 

Operand Stack:存放方法执行时的一些中间变量,JVM在执行方法时压入或者弹出这些变量。其实,操作数栈是方法真正工作的地方,执行方法时,局部变量数组与操作数栈根据方法定义进行数据交换。

 

Reference to Constant Pool:当JVM执行到需要常量池的数据时,就是通过这个引用来访问常量池的。栈帧中的数据还要负责处理方法的返回和异常。如果通过return返回,则将该方法的栈帧从Java栈中弹出。如果方法有返回值,则将返回值压入到调用该方法的方法的操作数栈中。另外,数据区中还保存中该方法可能的异常表的引用。

 

本地方法栈 

当程序通过JNI(Java Native Interface)调用本地方法(如C或者C++代码)时,就根据本地方法的语言类型建立相应的栈,此区域用于存储每个native方法调用的状态。 

堆(Heap) 

堆中存放的是程序创建的对象实例以及数组值的区域,可以认为Java中所有通过new创建的对象的内存都在此分配。当堆中的空间无法满足新建对象所需的内存开销,会有溢出现象而导致程序崩溃,为了避免溢出,当对象执行结束时,其占据的内存空间需要等待GC(Garbage Collection)进行回收,因此这个区域对JVM的性能影响很大。

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值