JVM介绍

来源:互联网 发布:3d人像建模软件 编辑:程序博客网 时间:2024/06/11 15:30

第一章 JVM介绍

JVM构成图

    JVM一般由类加载器、方法区、java堆、java虚拟栈、PC程序计数器、本地方法栈、执行引擎等组成。

        

JVM各个组成部分

2.1 类加载器

       类加载器ClassLoader:用来动态加载class文件到内存当中。

2.1.1 类加载器分类

      1)BootStrapClassLoader:称为启动类加载器,是Java类加载层次中最顶层的类加载器,负责加载JDK中的核心类库,如:rt.jar、resources.jar、charsets.jar、sunrsasign.jar、jsse.jar、jce.jar等(加载jdk/jre/lib/下的部分jar包以及jdk/jre/classes下的class文件)

       2)ExtensionClassLoader:称为扩展类加载器,负责加载Java的扩展类库,默认加载jdk/jre/lib/ext/目下的所有jar。

       3)AppClassLoader:称为系统类加载器,负责加载应用程序classpath目录下的所有jar和class文件。

       除了Java默认提供的三个ClassLoader之外,用户还可以根据需要定义自已的ClassLoader,自定义的ClassLoader都必须继承自java.lang.ClassLoader类(包括Java提供Extension ClassLoader和App ClassLoader)。但是Bootstrap ClassLoader不继承ClassLoader,因为它不是一个普通的Java类,底层由C++编写,已嵌入到了JVM内核当中。当JVM启动后,Bootstrap ClassLoader也随着启动,负责加载完核心类库后,并构造Extension ClassLoader和App ClassLoader类加载器。

2.1.2 类加载器原理

       ClassLoader使用的是双亲委托模型来搜索类的,每个ClassLoader实例都有一个父类加载器的引用(不是继承的关系,是一个包含的关系)。Bootstrap ClassLoader本身没有父类加载器,但可以用作其它ClassLoader实例的父类加载器。当一个ClassLoader实例需要加载某个类时,它会先把这个任务委托给它的父类加载器,这个过程是由上至下依次检查的,首先由最顶层的类加载器Bootstrap ClassLoader试图加载,如果没加载到,则把任务转交给Extension ClassLoader加载,如果也没加载到,则转交给App ClassLoader 进行加载,如果它也没有加载得到的话,则返回给委托的发起者,由它到指定的文件系统或网络等URL中加载该类。如果它们都没有加载到这个类时,则抛出ClassNotFoundException异常。否则将这个找到的类生成一个类的定义,并将它加载到内存当中,最后返回这个类在内存中的Class实例对象。

       为什么要使用双亲委托这种模型?因为这样可以避免重复加载,当父亲已经加载了该类的时候,就没有必要子ClassLoader再加载一次。考虑到安全因素,我们试想一下,如果不使用这种委托模式,那我们就可以随时使用自定义的String来动态替代java核心api中定义的String类型,这样会存在非常大的安全隐患,而双亲委托的方式,就可以避免这种情况,因为String已经在启动时就被类加载器(Bootstrcp ClassLoader)加载,所以用户自定义的ClassLoader永远也无法加载一个自己写的String,除非你改变JDK中ClassLoader搜索类的默认算法。

        JVM在搜索类的时候,如何判定两个class是相同?JVM在判定两个class是否相同时,不仅要判断两个类名是否相同,而且要判断是否由同一个类加载器加载的。只有两者同时满足的情况下,JVM才认为这两个class是相同的。就算两个class是同一份class字节码,如果被两个不同的ClassLoader实例所加载,JVM也会认为它们是两个不同class。

2.1.3 定义自已的ClassLoader

       自定义类加载器,分为两步:

       * 继承java.lang.ClassLoader

       * 重写父类的findClass方法

       因为JDK已经在loadClass方法中帮我们实现了ClassLoader搜索类的算法,当在loadClass方法中搜索不到类时,loadClass方法就会调用findClass方法来搜索类,所以我们只需重写该方法即可。如没有特殊的要求,一般不建议重写loadClass搜索类的算法。

2.2 执行引擎

       负责执行class文件中包含的字节码指令

2.3 内存区

       内存区(也叫运行时数据区),JVM运行的时候给操作所分配的内存区。运行时内存区主要可以划分为5个区域:

      1)方法区(全局共享):用于存储类结构信息的地方,包括常量池、静态变量、构造函数等。虽然JVM规范把方法区描述为堆的一个逻辑部分,但它却有个别名non-heap(非堆),所以大家不要搞混淆了。方法区还包含一个运行时常量池(Runtime Constant Pool)。

      2)Java堆(全局共享):存储java实例或者对象的地方。这块是GC的主要区域。方法区和堆是被所有java线程共享的。

      3)Java栈(线程独有):java栈总是和线程关联在一起,每当创建一个线程时,JVM就会为这个线程创建一个对应的java栈。在这个java栈中又会包含多个栈帧,每运行一个方法就创建一个栈帧,用于存储局部变量表、操作栈、方法返回值等。每一个方法从调用直至执行完成的过程,就对应一个栈帧在java栈中入栈到出栈的过程。所以java栈是线程私有的。

      4)本地方法栈(线程独有):和java栈的作用差不多,只不过是为JVM使用到的native方法服务的。

      5)程序计数器(线程独有):用于保存当前线程执行的内存地址。由于JVM程序是多线程执行的(线程轮流切换),所以为了保证线程切换回来后,还能恢复到原先状态,就需要一个独立的计数器,记录之前中断的地方,可见程序计数器也是线程私有的。

11 0
原创粉丝点击