Java内存模型:JVM内存结构与GC算法
一、Java内存模型概述
理解 Java内存模型(Java Memory Model, JMM)是Java虚拟机规范中定义的一组规则,它规定了线程如何以及何时可以看到其他线程共享变量的修改,以及如何同步访问共享变量。
区分 Java内存模型与JVM内存结构是两个不同的概念。JMM是关于多线程内存访问的抽象模型,而JVM内存结构是Java程序运行时内存的物理划分。
明确 JMM的主要目标是定义程序中各种变量的访问规则,以及在并发环境下如何保证共享变量的正确可见性和有序性。
二、JVM内存结构详解
认识 JVM运行时内存结构主要分为以下几个区域:
1. 程序计数器(PC Register)
定义 程序计数器是一块较小的内存空间,它是一个当前线程所执行的字节码行号指示器。
功能
- 存储下一条要执行的JVM指令地址
- 线程私有,不会出现内存溢出
2. 虚拟机栈(JVM Stack)
定义 虚拟机栈是Java方法执行的内存模型,每个方法执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。
特点
- 线程私有
- 栈深度由虚拟机栈大小决定
- 可能出现
StackOverflowError(线程请求栈深度超过虚拟机栈最大深度)和OutOfMemoryError(虚拟机栈可扩展时无法申请足够内存)
包含 每个栈帧包含:
- 局部变量表
- 操作数栈
- 动态链接
- 方法返回地址
- 额外信息
3. 本地方法栈(Native Method Stack)
定义 本地方法栈与虚拟机栈类似,区别是它为虚拟机使用到的Native方法服务。
特点
- 线程私有
- 可能出现
StackOverflowError和OutOfMemoryError
4. 堆(Heap)
定义 Java堆是Java虚拟机所管理的内存中最大的一块,它被所有线程共享,在虚拟机启动时创建。
特点
- 所有线程共享
- 唯一目的存放对象实例和数组
- 是GC管理的主要区域
- 可能出现
OutOfMemoryError
细分 堆内部可以细分为:
- 新生代(Eden区、From Survivor区、To Survivor区)
- 老年代
5. 方法区(Method Area)
定义 方法区用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。
特点
- 各线程共享
- 不进行垃圾收集
- 可能出现
OutOfMemoryError
替代 在JDK 8及以后版本,方法区被元空间(Metaspace)替代,使用本地内存而非JVM内存。
6. 运行时常量池(Runtime Constant Pool)
定义 运行时常量池是方法区的一部分,用于存放编译期生成的各种字面量和符号引用。
特点
- 各线程共享
- 可能出现
OutOfMemoryError
7. 直接内存(Direct Memory)
定义 直接内存不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域。
特点
- 通过NIO使用Native函数库直接分配堆外内存
- 可能出现
OutOfMemoryError - 分配和回收成本较高,但读写性能高
三、垃圾回收基础
1. 为什么需要垃圾回收
明确 在C/C++中,对象内存需要手动分配和释放,容易导致内存泄漏和野指针问题。
理解 Java垃圾回收器(GC)自动管理内存,回收不再使用的对象,避免内存泄漏。
2. 垃圾回收的意义
防止 内存溢出
提高 开发效率
增强 程序稳定性
3. 垃圾回收的判断方式
引用计数法
原理 给对象添加一个引用计数器,每当有一个地方引用它时,计数器加1;引用失效时,计数器减1;计数器为0时对象可回收。
缺点 无法解决对象循环引用问题
可达性分析算法
原理 通过一系列称为"GC Roots"的对象作为起点,从这些节点开始向下搜索,搜索所走过的路径称为引用链。
判定 当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。
GC Roots包括:
- 虚拟机栈中引用的对象
- 方法区中类静态属性引用的对象
- 方法区中常量引用的对象
- 本地方法栈中JNI引用的对象
4. 垃圾回收的四种引用级别
强引用(Strong Reference)
- 特点:只要强引用存在,垃圾回收器永远不会回收
- 场景:最常见的引用形式
软引用(Soft Reference)
- 特点:内存不足时会被回收
- 场景:内存敏感缓存
弱引用(Weak Reference)
- 特点:生存期短于强引用,只能存活到下一次垃圾回收前
- 场景:非必须对象
虚引用(Phantom Reference)
- 特点:不会决定对象的生命周期,主要用于跟踪垃圾回收过程
- 场景:跟踪对象被回收状态
四、GC算法详解
1. 标记-清除算法(Mark-Sweep)
原理
- 标记:遍历所有对象,标记所有需要回收的对象
- 清除:遍历整个内存区域,回收被标记的对象
优点
- 简单易实现
- 不需要移动对象
缺点
- 效率不高
- 产生内存碎片
2. 标记-整理算法(Mark-Compact)
原理
- 标记:遍历所有对象,标记所有需要回收的对象
- 整理:将存活对象向内存一端移动,直接清理端边界以外的内存
优点
- 没有内存碎片
- 适合老年代回收
缺点
- 移动对象开销大
- 效率较低
3. 复制算法(Copying)
原理 将可用内存按容量划分为大小相等的两块,每次只使用其中一块。当这块内存用完了,就将还存活的对象复制到另一块,再把已使用的内存空间一次清理掉。
优点
- 没有内存碎片
- 回收效率高
缺点
- 内存空间减半
- 存活对象多时,复制效率低
4. 分代收集算法
原理 根据对象存活周期的不同,将内存划分为几块,一般是把Java堆分为新生代和老年代。
新生代特点
- 对象存活时间短
- 适合复制算法
老年代特点
- 对象存活时间长
- 适合标记-清除或标记-整理算法
新生代回收过程
- 分配 新对象优先在Eden区分配
- 第一次GC 当Eden区满时,触发Minor GC,将存活对象复制到Survivor区
- 后续GC 每次Minor GC都会在两个Survivor区间移动对象,并增加对象的年龄计数器
- 晋升 当对象年龄达到阈值(默认15)或Survivor空间不足时,对象晋升到老年代
老年代回收
当老年代空间不足时,触发Major GC(或Full GC),通常采用标记-清除或标记-整理算法。
5. 增量收集算法与分区收集算法
增量收集算法
- 原理:将回收操作分批进行,减少应用停顿时间
- 目的:减少系统停顿
分区收集算法
- 原理:将整个堆划分为连续的不同小区间,每个区间独立回收
- 目的:控制回收时间,获得更短的停顿时间
五、GC实现与调优
1. HotSpot垃圾收集器
Serial收集器
特点
- 单线程工作
- 进行GC时,必须暂停所有用户线程
- 简单高效
- 适合客户端模式
ParNew收集器
特点
- Serial收集器的多线程版本
- 多线程回收
- 需要暂停用户线程
- 在服务端模式下首选新生代收集器
Parallel Scavenge收集器
特点
- 高吞吐量优先的收集器
- 多线程复制算法
- 可控制吞吐量
- 适合后台计算
Serial Old收集器
特点
- Serial收集器的老年代版本
- 单线程标记-整理算法
- 主要用于Client模式
Parallel Old收集器
特点
- Parallel Scavenge的老年代版本
- 多线程标记-整理算法
- 注重吞吐量
CMS(Concurrent Mark Sweep)收集器
特点
- 以获取最短回收停顿时间为目标
- 基于标记-清除算法
- 并发标记与并发清除
- 四个阶段:初始标记、并发标记、重新标记、并发清除
缺点
- 产生内存碎片
- CPU资源敏感
- 无法处理浮动垃圾
G1(Garbage-First)收集器
特点
- 面向服务端应用
- 并行与并发
- 空间整合
- 可预测停顿时间
设计理念
- 将整个Java堆划分为多个大小相等的独立区域(Region)
- 跟踪每个Region里垃圾的价值(回收空间大小与回收时间)
- 在有限时间内,回收价值最大的Region
2. GC调优
监控GC
- 使用
jstat命令监控GC情况 - 使用
jvisualvm可视化工具
分析GC日志
- 启用GC日志:
-Xloggc:gc.log -XX:+PrintGCDetails - 分析GC频率、停顿时间、吞吐量
调优原则
- 大多数应用不需要调优
- 明确调优目标:吞吐量还是响应时间
- 理解应用特性
常用参数调优
- 堆大小设置:
-Xms(初始堆大小)-Xmx(最大堆大小) - 新生代大小:
-Xmn、-XX:SurvivorRatio、-XX:NewRatio - GC类型选择:
-XX:+UseSerialGC、-XX:+UseParallelGC、-XX:+UseConcMarkSweepGC、-XX:+UseG1GC - GC日志配置:
-Xloggc:文件名 -XX:+PrintGCDetails -XX:+PrintGCTimeStamps
调优步骤
- 确定调优目标
- 基线测试
- 分析GC日志
- 确定瓶颈
- 调整参数
- 验证效果
六、总结
掌握 JVM内存结构和GC机制是Java开发者必备的基础知识,有助于编写更高效的程序并解决内存相关的问题。
理解 不同GC算法适用于不同的应用场景,根据应用需求选择合适的垃圾收集器至关重要。
实践 通过监控和分析GC日志,可以了解程序内存使用情况,并进行针对性调优,提高系统性能。

暂无评论,快来抢沙发吧!