1. JVM 架构
2. Class Loader
2.0 反射
Java 反射机制是在运行状态中,对于任意一个类,都能知道这个类的所有属性与方法;对于任意一个对象,都能调用它的任意方法和属性;动态获取信息以及调用对象的方法的功能称为 Java 的反射机制。
2.1 类从编译到执行的过程
- 编译器将 xxx.java 编译成 xxx.class 字节码文件
- ClassLoader 将字节码文件转换成 JVM 中的 Class 对象
- JVM 利用 Class 对象实例化为 xxx 对象
2.2 ClassLoader 的种类
- BootStrapClassLoader:加载核心库 java.* (C++ 编写)
- ExtensionClassLoader:加载扩展库 javax.* (Java 编写)
- ApplicationClassLoader:加载程序所在目录 (Java 编写)
2.3 类的加载
2.3.1 类加载方式
- 隐式加载:new
- 显式加载:forName, loadClass
- Class.forName 得到的 class 是已经初始化完成的
- ClassLoader.loadClass 得到的 class 是还没有进行连接的
2.3.2 类装载过程
1. 加载
- 通过 ClassLoader 加载 class 文件字节码,生成 Class 对象
2. 连接
- 校验:检查加载的 class 的正确性和安全性
- 准备:为类变量分配存储空间并设置变量初始值
- 解析:JVM 将常量池内的符号引用转换为直接引用
3. 初始化
- 执行类变量赋值和静态代码块
3. JVM 内存模型
3.1 按共享和独占分类
3.2 线程独占区域
3.2.1 程序计数器(PC 寄存器)(Program Counter Register)
- 当前线程所执行的字节码行号指示器(逻辑)
- 改变计数器的值来选取下一条需要执行的字节码指令
- 和线程是一对一关系,即“线程私有”
- 对 Java 方法计数,如果是 Native 方法则计数器值为 Undefined
- 不会发生内存泄漏
3.2.2 Java 虚拟机栈(Stack)
栈帧
每有一个方法执行,就会产生一个新的栈帧
- 局部变量表:执行过程中的所有变量
- 操作数栈:入栈、出栈、复制、交换和产生消费变量
- 动态链接:每个栈帧都包含一个指向运行时常量池中该栈帧所属性方法的引用,持有这个引用是为了支持方法调用过程中的动态连接
- 返回地址:方法执行过程中,有两种方式推出,1. 正常返回 2.异常退出
3.2.3 本地方法栈
3.3 共享区域
3.3.1 元空间 (MetaSpace) 与持久代 (PermGen) 的区别
- 元空间使用本地内存,而持久代使用的是 JVM 的内存
元空间相对于持久代的优势
- JDK7 和之前版本中,字符串常量池在持久代中,而持久代使用的是 JVM 内存,所以更容易发生性能问题和内存溢出
- 类和方法的信息大小难以确定,给永久代的大小指定带来困难
- 永久代会给 GC 带来不必要的复杂性
- 方便 HotSpot 与其他 JVM 如 Jroket 集成
3.3.2 堆 (Heap)
- 对象实例的分配区域
- GC 管理的主要区域
3.4 JVM 三大性能调优参数 -Xms -Xmx -Xss 的含义
- -Xss:规定了每个线程虚拟栈的大小
- -Xms:堆的初始值
- -Xmx:堆的最大值
3.5 内存分配策略的区别
- 静态存储:编译时确定每个数据目标在运行时的存储空间需求
- 栈式存储:编译时数据区不确定,运行时模块入口前确定
- 堆式存储:编译时和运行时都不确定,动态分配内存空间
3.6 栈和堆的区别
- 管理方式:栈自动释放,堆需要 GC
- 空间大小:栈比堆小
- 碎片相关:栈产生的碎片比堆小
- 分配方式:栈支持静态分配和动态分配,而堆只支持静态分配
- 效率:栈的效率比堆高