JVM包含哪几部分
JVM 主要由四大部分组成:ClassLoader(类加载器),Runtime Data Area(运行时数据区,内存分区),Execution Engine(执行引擎),Native Interface(本地库接口)
- ClassLoader:负责加载字节码文件即 class 文件,class 文件在文件开头有特定的文件标示,并且 ClassLoader 只负责class 文件的加载,至于它是否可以运行,则由 Execution Engine 决定。
- Runtime Data Area:是存放数据的,分为五部分:Stack(虚拟机栈),Heap(堆),Method Area(方法区),PC Register(程序计数器),Native Method Stack(本地方法栈)。
- Execution Engine:执行引擎,也叫 Interpreter。Class 文件被加载后,会把指令和数据信息放入内存中,Execution Engine 则负责把这些命令解释给操作系统,即将 JVM 指令集翻译为操作系统指令集。
- Native Interface:负责调用本地接口的。
JVM重要的类加载器?
JVM 中内置了三个重要的 类加载器
- BootstrapClassLoader(启动类加载器) :最顶层的加载类,由 C++实现,负责加载 JAVA_HOME/lib目录下的 jar 包和类或者被 -Xbootclasspath参数指定的路径中的所有类,并不继承自ClassLoader
- ExtensionClassLoader(扩展类加载器) :主要负责加载 JRE_HOME/lib/ext 目录下的 jar 包和类,或被 java.ext.dirs 系统变量所指定的路径下的 jar 包。
- AppClassLoader(应用程序类加载器) :程序中默认的加载器,负责加载当前应用 classpath 下的所有 jar 包和类。
如何自定义类加载器?
- 继承ClassLoader父类
- 要遵从双亲委派机制,重写findClass方法
- 注意不是重写loadClass方法,否则不会走双亲委派机制
双亲委派模型机制
即在类加载的时候,系统会首先判断当前类是否被加载过。已经被加载的类将直接返回,
加载的时候,首先会把该请求委派给父类加载器的 loadClass() 处理,因此所有的请求最终都应该传送到顶层的启动类加载器 BootstrapClassLoader 中。当父类加载器无法处理时,向下尝试加载
双亲委派模型优点是什么:
- 双亲委派模型避免了类的重复加载(JVM 区分不同类的方式不仅仅根据类名,相同的类文件被不同的类加载器加载产生的是两个不同的类)
- 保护核心API安全
jvm类加载过程
系统加载 Class 类型的文件主要三步:加载->链接->初始化。
- 连接过程又可分为三步:验证->准备->解析。
加载:
- 根据全类名获取此类的二进制字节流
- 将字节流所代表的静态存储结构转换为方法区的运行时数据结构
- 在内存中生成一个代表该类的 Class 对象,作为方法区这些数据的访问入口
ps:如果这个类的父类未被加载,会先加载父类
链接
验证: 验证文件格式、元数据、字节码、符号引用是否满足规范等
准备: 准备阶段是正式为静态变量(实例变量并没有)分配内存并设置默认值的阶段。(如果是加了final关键字,在编译器就设置好了初始值),否则,是在“初始化”阶段进行赋值的
解析: 解析阶段是虚拟机将常量池内的符号引用替换为直接引用(实际地址)的过程。
初始化:
- 初始化阶段是执行初始化方法
()方法的过程,是类加载的最后一步。 - 这一步 JVM 才开始真正执行类中定义的 Java 程序代码(字节码)。