JVM new Object() 都做了什么?类是怎么被加载到内

2021-05-08  本文已影响0人  进击的三文鱼

比起死板的理论,我更喜欢灵活的代码操作,毕竟程序不是静态的,程序是静态的,是千变万化的,每一行代码,在不同时间执行都可能产生不同的结果,每学一个理论,最终都需要践踏实地的实践,或是应用在项目中,或是自己写一个小demo,有了输出,才有了更好的收获。

今天写一些new Object()做了哪些事

首先简单写一个方法

public class ObjectDemo {
    public static void main(String[] args) {
        Object obj = new Object();
    }

}

然后找到这个类的class文件地址

执行javac - p ObjectDemo 输出字节码(汇编码)

 Code:
    0: new           #2                  // class java/lang/Object
    3: dup
    4: invokespecial #1                  // Method java/lang/Object."":
    7: astore_1
    8: return

上面就是计算机要执行的汇编码

一 从汇编码的角度解释这个过程

  1. new 首先jvm看如果没有对象的class那么就会去找这个class,然后进行加载对象中属性,并且将对象中的每一个属性,都放到在堆中开辟的内存空间中,并且产生一个指针(对象引用),并将这个指针压入栈中。
  2. dup 上一步将对象引用压入了栈,现在将这个引用复制一个,并且也压入栈,这时候栈中就有了两个对象引用,但是,他们的分工不同,一个是负责设置属性值的,另一个是负责对象引用的
  3. invokespecial 这一步是用来初始化的,比如构造方法,静态代码块啥的

二 从程序执行的角度

  1. 首先检查这个对象有没有在metaspace(元空间,他是描述对象信息的数据,在本地内存中分配)下,如果没有,那么就通过双亲委派机制,去查找这个对象的class,如果有就加载,如果没有就报错,ClassNotFoundException,是不是很熟悉
  2. 分配内存空间,找到对象了,就得给对象分配内存空间了,计算对象需要空间大小,分配空间
  3. 设置默认值
  4. 设置对象头
  5. 执行初始化方法,比如构造方法。

三 双亲委派

上面提到双亲委派机制,再简单说说这个机制,java的ClassLoader类加载器有三层

  1. Bootstrap classLoader: 主要负责加载核心的类库(java.lang.*等),构造ExtClassLoader和
  2. ExtensionClassLoader:主要负责加载jre/lib/ext目录下的一些扩展的jar。
  3. ApplicationClassLoader:主要负责加载应用程序的主函数类

然后通过一个类分析加载的流程

 protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException
    {
            // 首先,检查是否已经被类加载器加载过
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                try {
                    // 存在父加载器,递归的交由父加载器
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        // 直到最上面的Bootstrap类加载器
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }
                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    c = findClass(name);
                }
            }
            return c;
}

意思就是 加载一个类时,先看看自己能不能加载,如果不能加载就看是否存在父加载器,如果存在就判断父加载器能不能加载如果能就加载如果不能就继续向上,如果到顶了还是不能加载,那就向下,判断子加载器能不能加载,直到找到能够加载的子加载器,如果找不到就抛出异常。

为什么要这么干呢,主要是防止危险代码的植入,比如程序运行时,有人串改了String类的实现,那么jvm会判断这个类有没有被加载,如果加载了就不回加载这个类,那么就不用担心被串改了。

四 类加载

类加载是jvn工作的第一步,他的实现过程有几步

  1. 加载 将class文件以流的形式放到内存,并转化为Class实例
  2. 验证 验证这些类是否合规,类型是否正确
  3. 准备 对静态变量分配内存,赋值默认值
  4. 解析 解析类,确报对象之间相互引用的正确性
  5. 初始化 执行类构造器方法
上一篇下一篇

猜你喜欢

热点阅读