jvm之java程序从编写到执行的结构链路

jvm之java程序从编写到执行的结构链路


1.java前端编译器负责将java源代码编译为字节码-->前端编译器

2.java虚拟机负责将编译好的字节码装载进内部-->java类加载步骤和运行时区域

类加载过程:加载、链接、初始化

加载类加载阶段就是由类加载器负责根据一个类的全限定名来读取此类二进制字节流到JVM内部,并存储在运行时内存区的方法区内,然后将其转换成一个与目标类型对应的java.lang.Class对象实例,这个Class对象在日后就会作为方法区中该类的各种数据的访问入口。
链接将以加载到JVM中的二进制字节流的类数据信息合并到JVM的运行时状态中,连接阶段由验证、准备和解析3个阶段构成。验证阶段主要任务是验证类数据信息是否符合JVM规范。准备阶段的主要任务是为类中所有静态变量分配内存空间,并为其设置初始值。解析阶段将常量池中所有的符号引用全部转换成直接引用。不过JVM规范没有规定解析阶段一定要按顺序执行,所以解析阶段可以等到初始化之后再执行。
初始化JVM会将一个类中所有被static关键字标识的代码或者代码块统统执行一遍。

类加载器


Bootstrap Class Loader 也成为启动加载器,负责加载"JAVA_HOME/lib"目录中的所有类型
ExternalClassLoader 负责加载"JAVA_HOME/lib/ext"扩展目录中的所有类型
appClassLoader负责加载ClassPath下的所有类型

双亲委派模型

双亲委派模型(Parent Delegation Model):

类的加载过程采用双亲委托机制,这种机制能更好的保证 Java 平台的安全。
该模型要求除了顶层的Bootstrap class loader启动类加载器外,其余的类加载器都应当有自己的父类加载器。子类加载器和父类加载器不是以继承(Inheritance)的关系来实现,而是通过组合(Composition)关系来复用父加载器的代码。每个类加载器都有自己的命名空间(由该加载器及所有父类加载器所加载的类组成,在同一个命名空间中,不会出现类的完整名字(包括类的包名)相同的两个类;在不同的命名空间中,有可能会出现类的完整名字(包括类的包名)相同的两个类)

双亲委派模型的工作过程为:

1.当前 ClassLoader 首先从自己已经加载的类中查询是否此类已经加载,如果已经加载则直接返回原来已经加载的类。

每个类加载器都有自己的加载缓存,当一个类被加载了以后就会放入缓存, 等下次加载的时候就可以直接返回了。 

2.当前 classLoader 的缓存中没有找到被加载的类的时候,委托父类加载器去加载,父类加载器采用同样的策略,首先查看自己的缓存,然后委托父类的父类去加载,一直到 bootstrap ClassLoader.
3. 当所有的父类加载器都没有加载的时候,再由当前的类加载器加载,并将其放入它自己的缓存中,以便下次有加载请求的时候直接返回。

使用这种模型来组织类加载器之间的关系的好处:
主要是为了安全性,避免用户自己编写的类动态替换 Java 的一些核心类,比如 String,同时也避免了重复加载,因为 JVM 中区分不同类,不仅仅是根据类名,相同的 class 文件被不同的 ClassLoader 加载就是不同的两个类,如果相互转型的话会抛java.lang.ClassCaseException.

自定义类加载器

只需要继承抽象类ClassLoader并且重写 findClass()方法即可。把读进来的二进制数组转换成Class类的实例用到 defineClass()方法。

3.最后解释/编译为对应平台上的机器指令执行-->jvm执行引擎和垃圾回收GC

 Java字节码的执行有两种方式:
  1.即时编译方式:解释器先将字节码编译成机器码,然后再执行该机器码。 
  2.解释执行方式:解释器通过每次解释并执行一小段代码来完成Java字节码程 序的所有操作。 

hotspot vm 是jdk和openjdk中缺省自带的一款虚拟机。在hotspot vm内部,即时编译器和解释器是并存的。这是因为在虚拟机启动的时候,解释器可以首先发挥作用,而不必等待编译器全部编译完成再执行,这样可以省去许多不必要的编译时间。并且随着程序运行时间的推移,编译器逐渐发挥作用,根据热点探测功能,将有价值(频繁被调用的方法)的字节码编译成本地机器指令,以换取更高的程序执行效率。



发布了159 篇原创文章 · 获赞 75 · 访问量 19万+

猜你喜欢

转载自blog.csdn.net/xuehuagongzi000/article/details/70054576
今日推荐