zoukankan      html  css  js  c++  java
  • 浅谈JVM-图解类加载机制

    一、目录

    二、类加载机制流程

    1、什么是类加载机制?

      JVM把class文件加载到内存里面,并对数据进行校验、准备、解析和初始化,最终能够被形成被JVM可以直接使用的Java类型的过程。

    2、类加载流程图

    3、加载

    1. 将class文件加载在内存中。
    2. 将静态数据结构(数据存在于class文件的结构)转化成方法区中运行时的数据结构(数据存在于JVM时的数据结构)。
    3. 在堆中生成一个代表这个类的java.lang.Class对象,作为数据访问的入口。

    4、链接

     链接就是将Java类的二进制代码合并到java的运行状态中的过程。

    • 验证:确保加载的类符合JVM规范与安全。
    • 准备:为static变量在方法区中分配空间,设置变量的初始值。例如static int a=3,在此阶段会a被初始化为0,其他数据类型参考成员变量声明。
    • 解析:虚拟机将常量池的符号引用转变成直接引用。例如"aaa"为常量池的一个值,直接把"aaa"替换成存在于内存中的地址。
      • 符号引用:符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义地定位到目标即可。符号引用与虚拟机实现的内存布局无关,引用 的目标并不一定已经加载到内存中。
      • 直接引用:直接引用可以是直接指向目标的指针、相对偏移量或是一个能间接定位到目标的句柄。直接引用是与虚拟机实现的内存布局相关的,如果有了直接引用,那么引用的目标必定已经在内存中存在。

    5、初始化

      初始化阶段是执行类构造器<clinit>()方法。在类构造器方法中,它将由编译器自动收集类中的所有类变量的赋值动作(准备阶段的a正是被赋值a)和静态变量与静态语句块static{}合并,初始化时机后续再聊。

    6、使用

      正常使用。

    7、卸载

      GC把无用对象从内存中卸载。

    三、类加载与初始化时机

    1、类加载时机

      当应用程序启动的时候,所有的类会被一次性加载吗?估计你早已知道答案,当然不能,因为如果一次性加载,内存资源有限,可能会影响应用程序的正常运行。那类什么时候被加载呢?例如,A a=new A(),一个类真正被加载的时机是在创建对象的时候,才会去执行以上过程,加载类。当我们测试的时候,最先加载拥有main方法的主线程所在类。

    2、类初始化时机

     主动引用(发生类初始化过程)

    1. new一个对象。
    2. 调用类的静态成员(除了final常量)和静态方法。
    3. 通过反射对类进行调用。
    4. 虚拟机启动,main方法所在类被提前初始化。
    5. 初始化一个类,如果其父类没有初始化,则先初始化父类。

     被动引用(不会发生类的初始化)

    1. 当访问一个静态变量时,只有真正声明这个变量的类才会初始化。(子类调用父类的静态变量,只有父类初始化,子类不初始化)。
    2. 通过数组定义类引用,不会触发此类的初始化。
    3. final变量不会触发此类的初始化,因为在编译阶段就存储在常量池中。

    四、图解分析类加载

     1 public class ClassLoaderProduce {
     2     static int d=3;
     3     static{
     4         System.out.println("我是ClassLoaderProduce类");
     5     }
     6     public static void main(String [] args){
     7         int b=0;
     8         String c="hello";
     9         SimpleClass simpleClass=new SimpleClass();
    10         simpleClass.run();
    11     }
    12 }
    13 
    14 class SimpleClass{
    15     static int  a=3;
    16     static{
    17         a=100;
    18         System.out.println(a);
    19     }
    20 
    21     public SimpleClass(){
    22         System.out.println("对类进行加载!");
    23     }
    24 
    25     public void run(){
    26         System.out.println("我要跑跑跑!");
    27     }
    28 }

    步骤一:装载ClassLoaderProduce类,在方法区生成动态数据结构(静态变量、静态方法、常量池、类代码),并且在堆中生成java.lang.Class对象;然后进行链接

    步骤二:初始化:把static{}与静态变量合并存放在类构造器当中,对静态变量赋值。 1-5行执行完毕。

    步骤三:执行main方法,首先在栈里面生成一个main方法的栈祯,定义变量b、c,注意此处的变量b、c存储的常量池存储的变量的地址,如图所示。

    步骤四:创建SimpleClass对象;跟上面步骤类似:加载-链接-初始化。然后,调用run()方法的时候,它会通过classLoader局部变量的地址寻找到类的class对象并且调用run()方法

  • 相关阅读:
    小菜鸟学 MQ(三)
    小菜鸟 学MQ(二)
    小菜鸟学 MQ(一)
    CXF 自定义拦截器
    WebService 入门程序(一)
    查找满足条件的颜色并替换
    jsfl 巧用获取jsfl绝对路径,导入配置文件,注意配置文件无法改变舞台宽高
    jsfl 发布保存关闭
    jsfl 改变舞台宽高
    AS3 在不规则区域内拖动
  • 原文地址:https://www.cnblogs.com/qiuyong/p/6407418.html
Copyright © 2011-2022 走看看