本文内容总结于《深入理解Java虚拟机》,分为以下几个部分:
一、JVM的组成
二、垃圾回收策略
三、类加载
那,我们就赶紧开始吧
一、JVM的组成:
程序计数器:一块较小的内存区域,当前线程锁执行的字节码的行号指示器。
方法区:各个线程共享的内存区域,它用于储存已经被虚拟机加载的类信息、常量、静态变量、即使编译器编译后的代码等数据。
本地方法栈:服务于本地方法。
虚拟机栈:线程私有,每个方法对应一个栈帧,每次方法的执行以为着栈帧入栈再出栈的过程,所以虚拟机栈里存放的是局部变量、方法返回值、程序执行的状态等信息。
堆:被所有线程共享的一块内存区域,存放对象的实例,也是垃圾收集管理的主要区域。
常量池:方法区的一部分,存放编译期生成的各种字面量和符号引用
二、垃圾回收策略:
三、类加载
- 类加载的过程:
加载:JVM将目标文件(来源于ZIP包、网络等)编译成二进制字节流放进内存,并生成一个 java.lang.class对象。
验证:查看class文件的字节流是否符合JVM的规范(eg.是否以cafe babe开头)。
通过验证阶段后的字节流才会进入内存的方法区存储,后期的三个阶段是基于方法区的存储结构进行,不会再直接操作字节流。
准备:为类变量(静态变量,static修饰的变量)分配内存并初始化(赋予默认的初始值)。
解析:常量池的符号引用变为直接引用。
*符号引用:以一组符号来描述锁引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义地定位到目标即可。
*直接引用:是直接指向目标的指针、相对偏移量、或是一个能间接定位到目标的句柄。
初始化:静态变量初始化(类变量在准备阶段被赋予的是默认初始值、初始化阶段被赋予的是代码期望的值)。另一个角度表达:执行类构造器方法的全过程。 - 类加载器的组成:
(1) 启动类加载器(Bootstrap ClassLoader):加载\lib下的类库,使用C++编写。
(2) 扩展类加载器(Extension ClassLoader):加载\lib\ext下的类库。
(3) 应用类加载器(Application ClassLoader):加载用户类路径上所指定的类库。 - 双亲委派模型:
类加载器之间维护一种层级关系,自上往下分别为:启动类加载器,扩展类加载器,应用类加载器,自定义类加载器。
如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给自己的父类加载器,每一层类加载器都是如此,因此所有的请求都会传到顶层的启动类加载器中,只有当父类加载器反馈自己无法完成这个加载请求,子类加载器才会自己加载。
目的:Java类随着它的类加载器一起具备了一种带有优先级的层级关系,并且保证了类加载环境中每个类的唯一性,保证了Java程序的稳定性。