JVM中ClassLoader的学习

JVM中class loaderの学习


1、.class文件和jvm的关系

类的加载

全部的编译生成的.class文件都会被直接加载到JVM里面来吗**(并不**html

首先咱们明确一个概念,.class文件加载到jvm中意味着什么——类的初始化java

在虚拟机规范中,咱们规定,有且只有五种状况必须当即对类进行初始化git

  • 建立类的实例(new一个对象)访问某个类或者接口的静态变量,对静态变量赋值,调用类的静态方法
  • reflection
  • 启动类(main),直接使用Java.exe命令来运行某个主类(main方法)
  • 动态语言支持
  • 初始化子类,父类也会被初始化

.class的加载是消耗内存的,因此固然不能一次性的把全部的类加载再运行(原本就不快,这样作不是更慢),程序的base class会彻底加载到jvm里面来,至于其余的类,它们都是在须要的时候再加载的,这样是为了节省内存开销。github

怎么加载

class是经过类的加载器装在到jvm里面来的,Java默认有三种类加载器web

  • 引导类加载器(bootstrap class loader):它用来加载 Java 的核心库,是用原生代码来实现的,并不继承自 java.lang.ClassLoader
  • 扩展类加载器(extensions class loader):它用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。
  • 系统类加载器(system class loader):它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类。通常来讲,Java 应用的类都是由它来完成加载的。能够经过 ClassLoader.getSystemClassLoader()来获取它。

未命名文件.png

双亲委派模型apache

若是一个类收到了加载的请求,它首先不会本身加载这个类,而是会把请求委托给父加载器去完成,依次向上。(若是自身完成不了再依次向下,直到抛出ClassNotFound异常)bootstrap

advantage:缓存

防止内存中出现多份一样的字节码(从安全性角度来讲)tomcat

已经加载过的类,下次还会请求加载吗?

class loader在成功加载某个类以后,会把获得的java.lang.Class类的实例缓存起来。若是下次再遇见该类的加载请求,类加载器会直接使用缓存的类的实例,不会再次加载安全

类加载器是什么?

俄罗斯套娃

类加载器的Java类和全部其余的Java类同样,都是要经过类加载器来加载的。

对于开发人员编写的类加载器来讲,父类是加载该类加载器的Java类的类加载器

类加载器树状组织结构示意图

2、类的加载过程

加载器加载到jvm中,接下来其实又分了好几个步骤

  • 加载,查找并加载类的二进制数据,在Java堆中也建立一个java.lang.Class类的对象
  • 链接,链接又包含三块内容:验证、准备、初始化。
    • 验证,文件格式、元数据、字节码、符号引用验证;
    • 准备,为类的静态变量分配内存,并将其初始化为默认值;
    • 解析,把类中的符号引用转换为直接引用
  • 初始化,为类的静态变量赋予正确的初始值。

未命名文件 (1).png

3、类加载器和web容器

对于运行在 Java EE™容器中的 Web 应用来讲,类加载器的实现方式与通常的 Java 应用有所不一样。不一样的 Web 容器的实现方式也会有所不一样。以 Apache Tomcat 来讲,每一个 Web 应用都有一个对应的类加载器实例。该类加载器也使用代理模式,所不一样的是它是首先尝试去加载某个类,若是找不到再代理给父类加载器。这与通常类加载器的顺序是相反的。这是 Java Servlet 规范中的推荐作法,其目的是使得 Web 应用本身的类的优先级高于 Web 容器提供的类。这种代理模式的一个例外是:Java 核心库的类是不在查找范围以内的。这也是为了保证 Java 核心库的类型安全

In a Java environment, class loaders are arranged in a parent-child tree. Normally, when a class loader is asked to load a particular class or resource, it delegates the request to a parent class loader first, and then looks in its own repositories only if the parent class loader(s) cannot find the requested class or resource. Note, that the model for web application class loaders differs slightly from this, as discussed below, but the main principles are the same.

When Tomcat is started, it creates a set of class loaders that are organized into the following parent-child relationships, where the parent class loader is above the child class loader:

Bootstrap
          |
       System
          |
       Common
       /     \
  Webapp1   Webapp2 ...

Therefore, from the perspective of a web application, class or resource loading looks in the following repositories, in this order:

Bootstrap classes of your JVM /WEB-INF/classes of your web application /WEB-INF/lib/.jar of your web application System class loader classes (described above) Common class loader classes (described above)

If the web application class loader is configured with <Loader delegate="true"/> then the order becomes:*

Bootstrap classes of your JVM System class loader classes (described above) Common class loader classes (described above) /WEB-INF/classes of your web application /WEB-INF/lib/.jar of your web application

绝大多数状况下,Web 应用的开发人员不须要考虑与类加载器相关的细节。下面是几条简单的原则:

  • 每一个 Web 应用本身的 Java 类文件和使用的库的 jar 包,分别放在 WEB-INF/classesWEB-INF/lib目录下面。
  • 多个应用共享的 Java 类文件和 jar 包,分别放在 Web 容器指定的由全部 Web 应用共享的目录下面。
  • 当出现找不到类的错误时,检查当前类的类加载器和当前线程的上下文类加载器是否正确。

ps.用的图床挂了,你们先将就着看下,后续再改

Demo

跟着博客作的一个ClassLoader小demo https://github.com/JhinQaQ/Classloader

参考资料

Java虚拟机底层原理知识总结 https://github.com/doocs/jvm

tomcat7.0 ClassLoader http://tomcat.apache.org/tomcat-7.0-doc/class-loader-howto.html

深刻探讨Java类加载器 https://www.ibm.com/developerworks/cn/java/j-lo-classloader/

Java类加载器的使用场景有哪些?https://www.zhihu.com/question/46719811

相关文章
相关标签/搜索