JVM结构——类加载器
JVM启动时或类运行时将需要的class加载到JVM中。
classloader
java类加载器,主要作用是将class加载到JVM中,同时考虑由谁加载。
bootstrapclassloader
顶层类加载器,内嵌到JVM中,在JVM启动时会初始化该classloader,主要用于读取java核心类库jre/lib/rt.jar中的所有class文件,这个jar文件包含了java规范定义的所有接口及实现
extensionclassloader
读取java的一些扩展类库,如jre/lib/ext/*.jar的包等
appclassloader
程序默认类加载器,读取classpath下指定的所有jar包或目录的类文件。
customclassloader
用户自定义编写,用来读取指定类文件,还可以在加载class文件前对文件进行加密、编码等等。
加载机制之一:双亲委派模型
当父亲已经加载了该类的时候,子classloader就不用再加载一次,避免重复加载,节约资源,JVM根据类名+包名+classloader的实例ID来判断两个类是否相同,是否已加载。
注意:bootstrapclassloader具备有extensionclassloader父类加载器的功能,但是他并不是他的父类加载器,原因是在默认classloader的loadclass方法中,当parent为null的时候,他会交给顶层类加载器bootstrapclassloader来处理,而extensionclassloader并没有重写默认的loadclass方法,所以extensionclassloader也会调用bootstrapclassloader类加载器来加载。
类加载器的三个重要方法
loadclass
classloader加载类的入口,此方法负责加载指定名称的类,它先从已加载的类中寻找,没有继续从父classloader中寻找,还没有则从bootstrapclassloader中寻找,最后再调用findclass来寻找,如果扔未获取到该对象,则抛出ClassNotFoundException异常
findclass
直接抛出ClassNotFoundException异常,因此需要通过覆盖loadclass或此方法来以自定义的方式加载相应的类。
defineclass
将二进制字节码转换成class对象
注意:自定义classloader需要重写findclass而不是loadclass或者其他方法,原因是JDK中已经在loadclass方法中帮我们实现了classloader搜索类的方法判断。当loadclass方法中搜索不到该类时,loadclass就会调用findclass来搜索类,所以我们只需要重写findclass即可。
其他
Web容器加载机制:J2EE规范推荐每个模块的类加载器先加载本类的内容,加载不到再回到parent类加载器尝试加载,即反转委派原则。
重复加载和回收:一个class可以被不同的classloader重复加载,但同一个class只能被同一个classloader加载一次。当某个classloader加载的所有类实例化的所有对象都被回收,则该classloader也会被回收。
JVM结构——执行引擎
负责执行class文件中包含的字节码指令。
JVM结构——内存区
方法区(Method Area):用于储存类结构信息的地方,包括常量池,静态变量,构造函数等。
Java堆(Heap):储存java实例或者对象的地方。方法区和堆是被所有线程共享的。
Java栈(Stack):java栈总是和线程关联在一起,每当创建一个线程时,jvm就会为这个线程创建一个对应的java栈,在这个java栈中又会包含多个栈帧,每运行一个方法就会创建一个栈帧,用于存储局部变量、操作栈,方法返回值等。每一个方法从调用直至执行完成的过程,就对应一个栈帧在java栈中入栈到出栈的过程,所以java栈是线程私有的。
程序计数器(PC Register):用于保存当前线程执行的内存地址,由于jvm是多线程执行的,为了保证线程切换回来,还能恢复到原先状态,就需要一个独立的计数器,记录之前线程中断的地方,可见程序计数器也是线程私有的。
JVM结构——本地方法接口
主要是调用C或C++实现本地方法及返回结果。