《Java溯本求源》-Java运行原理

几乎所有人学习一门编程语言都是从打印“Hello World”开始的,我学习Java也不例外。那么当在屏幕中显示了”Hello World“这几个单词时,我们有没有想过Java到底是怎么做到的呢?本文中我将尝试对Java的运行原理溯本求源,为大家解开这个疑惑。

一、几个基本名词概念

JDK、JRE、JVM

1,JDK(Java Development Kit),Java开发工具包。JDK是给开发人员使用的。JDK中包含了基础的类库,以及编译、打包等程序。

2,JRE(Java Runtime Environment),Java运行时环境。包括了Java的核心类库、Jvm等运行Java程序所必须的环境。但不包括JDK中的编译(javac)、打包(jar)等程序。

3,JVM(JAVA Virtual Machine),Java虚拟机。是整个Java运行原理的核心。JVM有着自己的指令系统,它负责运行Java程序,并最终”翻译“成操作系统CPU的指令执行。不同操作系统上的JVM实现是不一样的,JVM屏蔽了不同操作系统的差异,为JAVA运行提供了统一的接口。这也是Java跨平台的原因。

请注意: JDK和JRE都不是一个程序,前者是一个开发工具包,而JRE是一个运行时环境。真正负责运行Java程序的是JVM。三者之间的关系如下图所示:

JDK、JRE、JVM三者的区别与联系 - 以德糊人 - ——挨踢民工 Playkid——


二、Java程序运行过程

Java程序运行的基本过程是这样的:编辑代码---> 编译代码--->执行代码。 

编辑代码很好理解,使用普通的文本编辑器就可以,但专业的IDE显然更合适,因为它可以帮助我们完成诸如语法检查,自动代码提示等一大堆繁琐而且容易出错的工作。编辑好的Java源代码为 .java文件

编译java代码是由JDK的编译工具完成的,也就是javac.exe。 实际上就是将.java文件按照一定的规则编译成JVM可以识别的.class字节码文件。

执行Java代码由JVM完成,简单来说就是加载.class字节码文件,解释程序指令,并最终翻译成计算机可以识别的CPU指令。


三、JVM的运行原理

JVM是Java的运行核心,所以我们有必要了解JVM的运行原理。

首先来看看JVM的组成结构:


1,Class Loader 类加载器

Java 中的所有类,必须被装载到 JVM 中才能运行,这个装载工作是由 JVM 中的类装载器完成的,类装载器所做的工作实质是把类文件从硬盘读取到内存中。JVM的类加载是通过ClassLoader及其子类来完成的,类的层次关系和加载顺序可以由下图来描述:

    

1)Bootstrap ClassLoader /启动类加载器

负责加载$JAVA_HOME中jre/lib/rt.jar里所有的class,由C++实现,不是ClassLoader子类

2)Extension ClassLoader/扩展类加载器

负责加载java平台中扩展功能的一些jar包,包括$JAVA_HOME中jre/lib/*.jar或-Djava.ext.dirs指定目录下的jar包

3)App ClassLoader/ 系统类加载器

负责记载classpath中指定的jar包及目录中class

4)Custom ClassLoader/用户自定义类加载器(java.lang.ClassLoader的子类)

属于应用程序根据自身需要自定义的ClassLoader,如tomcat、jboss都会根据j2ee规范自行实现ClassLoader

在这里,需要着重说明的是,JVM在加载类时默认采用的是双亲委派机制。通俗的讲,就是某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。

2,运行数据区

运行数据区分为5个部分:

1)PC寄存器

PC寄存器是用于存储每个线程下一步将执行的JVM指令,如该方法为native的,则PC寄存器中不存储任何信息。

2)JVM栈

JVM栈是线程私有的,每个线程创建的同时都会创建JVM栈,JVM栈中存放的为当前线程中局部基本类型的变量(java中定义的八种基本类型:booleancharbyteshortintlongfloatdouble)、部分的返回结果以及Stack Frame,非基本类型的对象在JVM栈上仅存放一个指向堆上的地址

3)堆(heap)

它是JVM用来存储对象实例以及数组值的区域,可以认为Java中所有通过new创建的对象的内存都在此分配,Heap中的对象的内存需要等待GC进行回收。

4)方法区域(Method Area

方法区域存放了所加载的类的信息(名称、修饰符等)、类中的静态变量、类中定义为final类型的常量、类中的Field信息、类中的方法信息,当开发人员在程序中通过Class

5)运行时常量池(Runtime Constant Pool)

存放的为类中的固定的常量信息、方法和Field的引用信息等,其空间从方法区域中分配。

6)本地方法堆栈(Native Method Stacks

JVM采用本地方法堆栈来支持native方法的执行,此区域用于存储每个native方法调用的状态。

3,执行引擎

VM通过执行引擎来完成字节码的执行,在执行过程中JVM采用的是自己的一套指令系统,每个线程在创建后,都会产生一个程序计数器(pc)和栈(Stack)。

4,垃圾收集器(GC)

JVM负责程序运行的内存管理,并及时回收那些无用对象所占用的内存空间。关于JVM的垃圾回收机制,将来有时间再详细解答。

到此,我们可以梳理下JVM的生命周期了:

1,启动。启动一个Java程序时,一个JVM实例就产生了,任何一个拥有public static void main(String[] args)函数的class都可以作为JVM实例运行的起点

2, 运行。main()作为该程序初始线程的起点,任何其他线程均由该线程启动。JVM内部有两种线程:守护线程和非守护线程,main()属于非守护线程,守护线程通常由JVM自己使用,java程序也可以标明自己创建的线程是守护线程

3,消亡。当程序中的所有非守护线程都终止时,JVM才退出;若安全管理器允许,程序也可以使用Runtime类或者System.exit()来退出


四、总结

本文简单阐述了Java程序的执行过程,JVM的运行原理及一些基本概率。写下这边Blog主要是为了总结学习的知识,留下记号,也方便以后复习。本文的内容绝大部分都收集于网络中,欢迎大家转载。当然其中肯定会有还有一些瑕疵错误,欢迎指正。我也会不断完善。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值