Java虚拟机(JVM)详解
Java虚拟机(JVM)详解
- JVM内存结构
- 垃圾收集算法
- 标记-清除 算法
- 复制 算法
- 标记 - 整理 算法
- 分代收集算法
- 类加载
- 类加载过程
- 加载器类型
- 双亲委派模型
- Java对象如何判断存活
- 引用计数法
- 可达性分析法
- 方法分派模型
- 静态分派
- 动态分派
JVM内存结构
- 方法区:储存着已被虚拟机加载的类信息,常量,静态变量等数据。线程共享。
抛出的异常:OutOfMemoryError - 程序计数器:是当前线程执行字节码的指示器,包括分支、循环、跳转、异常处理、线程恢复等功能。内存空间小,且线程私有。
抛出的异常:没有规定任何 OutOfMemoryError 情况的区域 - 堆:用于存放对象实例,是垃圾收集器管理的主要区域。
抛出的异常:OutOfMemoryError - 本地方法栈: 主要是Native方法服务。
抛出的异常:StackOverflowError,OutOfMemoryError - 虚拟机栈:用于支持方法的调用与执行。线程私有,生命周期与线程相同。
抛出的异常:StackOverflowError,OutOfMemoryError - 运行时常量池(额外点):属于方法区一部分,用于存放编译期生成的各种字面量和符号引用。
- 直接内存(额外点):基于通道和缓冲区的I/O方式,通过使用Native函数库直接分配的堆外内存。
StackOverflowError:线程请求的栈深度大于虚拟机所允许的深度。
OutOfMemoryError:如果虚拟机栈可以动态扩展,而扩展时无法申请到足够的内存。
垃圾收集算法
标记-清除 算法
- 过程:
- 标记阶段:标记出所有需要回收的对象;
- 清除阶段:统一清除(回收)所有被标记的对象
- 缺点:当程序需要分配大内存块的时候,无法找到适合的连续内存块,从而会导致触发没必要的垃圾收集行为。
复制 算法
- 过程:
- 将内存分为大小相等的两块,每次使用其中一块。
- 当使用的这块内存用完,就将当前这块内存上还存活的对象复制到另一块还没试用过的内存上。
- 将之前使用的那块内存清理掉。
- 缺点:
- 使用的内存缩小为原来的一半。
- 在对象存活率都较高的情况下,需要做过多复制操作,从而导致效率会变低。
标记 - 整理 算法
- 过程:
- 标记所有需要回收的对象
- 把所有存活的对象移动到一端
- 统一清除掉回收端的对象
分代收集算法
- 过程:
- 根据对象存活周期的不同将 Java堆内存分为:新生代和老年代 。
新生代:每次垃圾回收都有大量对象死去,只有少量存活,选用复制算法。
老年代:老年代中对象存活率较高、没有额外的空间分配对它进行担保。所以必须使用“标记-清除”或者“标记 -整理"算法回收。
- 新生代与老年代的区分流程
- 新建的对象会被优先分配到新生代的Eden区、From Survivor区
- 经过第一次 Minor GC后,若对象仍然存活,将会被移到To Survivor区。
- 在 To Survivor 区每经过一轮Minor GC ,该对象的年龄就+1。
- 当对象年龄达到一定时(阈值默认为15),就会被移动到老年代。
类加载
类加载过程
简介:加载 -> 验证 -> 准备 -> 解析 -> 初始化
- 加载:将class文件加载到虚拟机或者储存到方法区内。
- 验证:检查加载的class文件是否符合虚拟机的要求。包括文件格式验证,元数据验证,字节码验证,符号引用验证。
- 准备:给类变量分配内存以及设置初始值。
- 解析:将常量池中的符号引用替换成直接引用。包括类或接口、字段、类方法、接口方法、方法类型、方法句柄等
- 初始化:执行类中的 Java 代码。
加载器类型
- 启动类加载器:加载lib或-Xbootclasspath的路径并且是被虚拟机识别的类库的类。
- 扩展类加载器:加载lib\ext或被java.ext.dirs所指定的路径中的所有类库
- 应用程序类加载器:负责加载用户类路径上所指定的类库。
双亲委派模型
简介:双亲委派模型的核心思想是当一个类加载器接收到类加载请求时,它不会立即自己加载,而是将请求委派给父类加载器。
Java对象如何判断存活
引用计数法
简介:给对象添加一个引用计数器,每当有一个地方引用它时,计数器 +1,引用失效则 -1。如果计数器不为 0 时,判断该对象存活,否则判断为死亡(计数器 = 0)
可达性分析法
简介:以“GC Roots”对象作为起点,从这些起点开始往下搜索,搜索所走过的路径称为引用链(Reference Chain)。当一个对象没有和任何引用链相连时,即称为该对象不可达,即可以认为该对象死亡。
方法分派模型
静态分派
简介:编译期(由编译器决定调用目标方法)
典型场景:方法重载(Overloading)
动态分派
简介:运行期(由 JVM 根据对象实际类型决定调用目标方法)。
典型场景:方法重写(Overriding)