JVM- 类加载应该知道的事

126 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第5天,点击查看活动详情

字节码加载

image.png

方法区

作用:

  • 在内存中,存放class文件的逻辑结构,也就是类的元(meta)信息

包括:

  • 常量池,类信息,字段,方法,属性等
方法区的实现

JVM只是一个规范,所以方法区也只是一个规范,有不同实现方式:

  • 在java8以前的版本,被实现“永久代”,名称与堆中的“年轻代”,“老年代”相对应和堆一样,同为线程共有,但又没有垃圾回收,所以被称为“非堆”
  • 在java8以后的版本,被称为元空间(meta space),直接放在本地内存,所以理论上没有大小限制。

Java程序的双亲委派模型

image.png

  • BootstrapClassLoader 启动类加载器,jvm内部C++实现,无法获取
  • ExtensionClassLoader 扩展类加载器
  • ApplicationClassLoader 应用程序类加载器

类加载的过程:

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

Android程序的双亲委派模型

image.png

ClassLoader源码

//真正从字节码文件中根据类名,返回class实例的方法,应该被子类实现或者重写
protected Class<?> findClass(String name) throws ClassNotFoundException {
    throw new ClassNotFoundException(name);
}

loadClass方法

//外部通过这个方法获取class的实例
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);//递归调用父类加载器的loadclass
                } else {
                    c = findBootstrapClassOrNull(name);
                }
            } catch (ClassNotFoundException e) {
            }

            if (c == null) {
                c = findClass(name);
            }
        }
        return c;
}

加载自己写的Object类

image.png

class的双亲委派模型的好处

  • 能够对类划分优先级层次关系
  • 避免类的重复加载
  • 沙箱安全机制,避免代码被篡改