Java 内存模型:JVM 调优与垃圾回收
·
Java 内存模型:JVM 调优与垃圾回收
1. Java 内存模型(JMM)概述
Java 内存模型定义了多线程环境下共享变量的访问规则,确保线程安全。核心组件包括:
- 堆(Heap):存储对象实例(所有线程共享)
- 栈(Stack):存储局部变量和方法调用(线程私有)
- 方法区(Method Area):存储类信息、常量池
- 程序计数器(PC Register):记录当前线程执行位置
- 本地方法栈(Native Stack):支持本地方法调用
内存访问遵循 happens-before 原则,保证可见性: $$ \text{若操作 } A \text{ 先于 } B,\text{ 则 } A \text{ 的结果对 } B \text{ 可见} $$
2. 垃圾回收(GC)机制
核心算法
- 标记-清除(Mark-Sweep)
分标记存活对象、清除未标记对象两步,会产生内存碎片 - 复制(Copying)
将存活对象复制到新内存区($ \text{空间利用率} = 50% $) - 标记-整理(Mark-Compact)
标记后移动对象消除碎片 - 分代收集(Generational)
JVM 默认策略,将堆分为:- 新生代(Young Generation):使用复制算法(Eden + Survivor 区)
- 老年代(Old Generation):使用标记-清除/整理算法
GC 触发条件
- Minor GC:新生代空间不足时触发
- Major GC:老年代空间不足时触发(通常伴随 Full GC)
- Full GC:整个堆和方法区回收($ \text{停顿时间长} $)
3. JVM 调优策略
关键参数
| 参数 | 作用 | 示例值 |
|---|---|---|
-Xms |
初始堆大小 | -Xms2g |
-Xmx |
最大堆大小 | -Xmx4g |
-XX:NewRatio |
新生代/老年代比例 | -XX:NewRatio=3 |
-XX:SurvivorRatio |
Eden/Survivor 比例 | -XX:SurvivorRatio=8 |
-XX:+UseG1GC |
启用 G1 回收器 | - |
调优步骤
- 监控工具
使用jstat、jvisualvm或GC logs分析:jstat -gcutil <pid> 1000 # 每秒输出GC数据 - 识别瓶颈
- 频繁 Full GC → 检查内存泄漏或老年代过小
- 长 GC 停顿 → 调整回收器(如切换 G1)
- 优化策略
- 对象分配优化:减少大对象直接进老年代
- 选择合适的 GC:
- CMS:低停顿(
-XX:+UseConcMarkSweepGC) - G1:大堆场景($ \text{预测停顿时间} $)
- CMS:低停顿(
- 线程本地分配(TLAB):减少堆竞争
4. 实战示例
内存泄漏检测代码:
public class MemLeakDemo {
static List<byte[]> list = new ArrayList<>();
public static void main(String[] args) throws InterruptedException {
while (true) {
list.add(new byte[1024 * 1024]); // 每秒分配1MB
Thread.sleep(1000);
}
}
}
调优建议:
- 添加 JVM 参数:
-Xmx100m -XX:+HeapDumpOnOutOfMemoryError - 当 OOM 时生成堆转储文件,用 MAT 工具分析泄漏点
最佳实践:遵循 $ \text{最小化内存占用} $ 原则,通过
-XX:MaxTenuringThreshold控制对象晋升老年代的年龄阈值,结合 ZGC(-XX:+UseZGC)实现亚毫秒级停顿。
更多推荐
所有评论(0)