一、核心原理与结构
- 内存模型定义
- 线程共享区域,所有对象实例和数组存储在此
- JVM启动时通过-Xms和-Xmx参数设置初始/最大堆大小
- 典型结构划分(以G1收集器为例):
- 年轻代(Young Generation)≈1/3堆内存
- Eden区(默认8:1:1)
- From Survivor
- To Survivor
- 老年代(Old Generation)≈2/3堆内存
- 元空间(Metaspace):存储类结构信息(Java 8+)
- 年轻代(Young Generation)≈1/3堆内存
- 对象分配流程
// 对象分配示意图
Person p = new Person();
// 1. 在Eden区分配内存(默认)
// 2. 若Eden空间不足触发Minor GC
// 3. 存活对象进入Survivor区
// 4. 经过15次GC后晋升至老年代
二、线程安全特性分析
- 堆内存线程安全特性
- 本质是共享资源:多个线程可同时访问同一对象
- 例外情况:
- 不可变对象(final字段)
- 本地线程变量(ThreadLocal)
- 使用synchronized/volatile的正确同步对象
- CAS原子操作保护的对象
- 线程安全问题示例
// 非线程安全示例
public class Counter {
public int count = 0;
}
// 多线程访问
Thread t1 = new Thread(() -> counter.count++);
Thread t2 = new Thread(() -> counter.count++);
// 线程安全改造
public class SafeCounter {
private volatile int count;
public synchronized void increment() { count++; }
}
三、内存分配机制
- 分配策略
- TLAB(Thread-Local Allocation Buffer):
- 每个线程独占Eden区小块内存(默认2%堆大小)
- 减少锁竞争(无需CAS操作)
- 可通过-XX:+/-UseTLAB启用/禁用
- 大对象处理
- 直接分配到老年代(超过-XX:PretenureSizeThreshold)
- 避免Eden区频繁复制
四、垃圾回收机制
-
核心算法对比
算法类型 优点 缺点 典型应用 复制算法 无碎片,高效 空间利用率低(50%) 年轻代 标记-清除 实现简单 产生内存碎片 不常单独使用 标记-整理 无碎片,内存连续 整理阶段耗时 老年代 分代收集 平衡性能与效率 算法复杂 标准实现方案 -
收集器选择指南
- Serial(单线程):适合单核客户端应用
- Parallel(多线程):吞吐优先(-XX:+UseParallelGC)
- CMS(并发):低延迟(-XX:+UseConcMarkSweepGC)
- G1(分区):平衡吞吐与延迟(-XX:+UseG1GC)
- ZGC/Shenandoah:超大堆(<1TB)低延迟
五、内存溢出解决方案
- 堆溢出诊断流程
OutOfMemoryError: Java heap space
↓
生成堆转储:jmap -dump:live,format=b,file=heap.hprof <pid>
↓
分析工具:
- jhat heap.hprof
- VisualVM (OQL查询)
- MAT (支配树分析)
↓
定位泄漏根源:
- 长生命周期集合类
- 未关闭的资源缓存
- 静态集合引用
- 典型优化策略
-
对象复用:使用对象池(如数据库连接池)
-
集合优化:
// 合理初始化容量 List<String> list = new ArrayList<>(1024); // 及时清理不再使用项 list.clear(); -
缓存管理:使用WeakHashMap/SoftReference
-
内存泄漏预防:
// 错误示例 static Map<String, Object> cache = new HashMap<>(); // 修正方案 static Map<String, SoftReference<Object>> cache = new HashMap<>();
六、调优最佳实践
- 参数配置参考
# 标准调优参数
java -Xms4g -Xmx4g \
-XX:NewRatio=2 \
-XX:SurvivorRatio=8 \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=200 \
-XX:G1HeapRegionSize=4M \
-XX:+PrintGCDetails ...
- 监控指标分析
- 关键指标:
- Young GC频率(每秒次数)
- Full GC耗时(应<1s)
- 堆内存使用率(<70%)
- 工具推荐:
- jstat -gcutil 1s
- VisualVM 内存快照
- Prometheus + Grafana 监控面板
七、高级特性解析
- 压缩普通对象指针(CompressedOops)
- 32位JVM自动启用
- 64位JVM默认启用(-XX:+UseCompressedOops)
- 节省内存开销:对象头由12B→8B
- 内存对齐填充(Padding)
- 对象大小按8字节对齐
- 避免False Sharing(伪共享)问题
- 通过-XX:+UseBiasedLocking优化锁竞争
八、执行流程示意图
对象创建 → 在Eden区分配
↓
Minor GC → 存活对象进入Survivor
↓
Survivor区满 → 晋升至老年代
↓
Major GC → 清理老年代
↓
Full GC → 整个堆回收(老年代+年轻代)
九、常见误区澄清
- "堆越大越好?"
- 过大堆:
- 增加GC停顿时间
- 降低吞吐量
- 增加OOM风险
- 优化建议:根据应用负载测试确定合适大小
- "所有对象都在堆?"
- JVM逃逸分析优化:
- 栈上分配(不逃逸对象)
- 同步消除(无竞争锁)
- 克隆消除(相同对象)
附:典型配置参考
# 电商秒杀服务配置
java -Xms8g -Xmx8g \
-XX:NewSize=3g \
-XX:MaxNewSize=3g \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=100 \
-XX:ParallelGCThreads=4 \
-XX:ConcGCThreads=2 ...