00:00

00

2019/1/1

JVM类加载机制和内存模型

一.JVM类加载机制

  首先需要了解一下类加载器(ClassLoader)

    ClassLoader是Java的一个核心组件,它主要作用是从系统外部获得Class二进制数据流,然后将数据流装载到系统,交给JVM进行连接,初始化等操作,所有的Class都是有ClassLoader进行加载的。

    点开ClassLoader类,如下图所示:

    

  类加载器种类

    启动类加载器(BootStrapClassLoader):它用来加载 Java 的核心类,如java.xxx。

    扩展类加载器(ExtensionsClassLoader):它负责加载JRE的扩展目录,如javax.xxx。

    应用类加载器(AppClassLoader):它一般用来加载程序所在目录下的类。

    自定义类加载器:通过继承ClassLoader类实现自定义类加载器。

  双亲委派机制:

    虚拟机是根据类的全限定名来加载类的,那么有个问题,如果同时存在两个或多个全限定名完全一致的情况下,该如何选择加载哪个类?如何判断该类是否被加载过了?这都是双亲委派机制能做的。

    下图是双亲委派机制的实现(这是ClassLoader中的loadClass方法),很明显,parent也是一个类加载器。

    

    双亲委派机制原理:

      1.一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,直到启动类加载器

      2.启动类加载器检查能不能加载(使用findClass()方法),能就加载(结束);否则,抛出异常,通知子加载器进行加载。

    双亲委派机制的优点是:

      1.安全,可避免用户自己编写的类动态替换Java的核心类,如java.lang.String
      2.避免全限定命名的类重复加载(使用了findLoadClass()判断当前类是否已加载)

  附:Java跨平台实现的原理:Java源码首先被编译成字节码(不同平台编译后的字节码是一样的,因此在不同平台上运行时不需要重新编译),再由不同平台的JVM进行解析,将字节码转换成具体平台上的机器指令。

  类加载流程:

    加载:通过ClassLoader加载class文件字节码,生成Class对象

    连接:检查加载的class文件的正确性和安全性;为类变量分配存储空间并设置类变量初始值;JVM将常量池内的符号引用转换为直接引用

    初始化:执行类变量赋值和静态代码块

  类加载的方式:

    隐式加载:通过new关键字来创建实例对象。

    显式加载:

      通过Class.forName()来加载类,它得到的是已经初始化完成的class

      通过类加载器的loadClass()方法来加载类,它得到的class还没有完成连接过程

二.JVM内存模型

   

  所有线程共享的内存数据区:方法区,堆。而虚拟机栈,本地方法栈和程序计数器都是线程私有的。

     1、存放于栈中的:

      每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(如变量的名字)。

      每个栈中的数据(基础数据类型和对象引用)都是私有的,其他栈不能访问。

      方法的形式参数,方法调用完后从栈空间回收。

      引用对象的地址,引用完后,栈空间地址立即被回收,堆空间等待GC。

     2、存放于堆中的:

       存储的全部是对象,每个对象包含一个与之对应的class信息

      Jvm只有一个堆区(heap)被所有线程共享,堆区中不存放基本类型和对象引用,只存放对象本身

     3、存放于方法区中的:

      存放线程所执行的字节码指令

      跟堆一样.被所有线程共享.方法区包含:static变量

  注意:Class实例在jdk1.6及之前是存放在方法区中, 在jdk1.7及之后存放在堆中

     常量池在jdk1.6及之前是存放在方法区中,在jdk1.7存放在堆中,在jdk1.8存放在元空间中

posted @ 2019-07-21 19:02  认真的杨先森  阅读(1454)  评论(0编辑  收藏  举报