一、什么是内存溢出?
想象你的手机只有64G存储,当照片和视频塞满后,系统就会提示"存储空间不足"。JVM内存溢出也是类似情况:Java程序运行时需要的内存超过了JVM分配的上限,就像往500ml的杯子里倒600ml水,多出来的部分就会溢出。
常见报错长这样:
// 技术栈:Java 8
public class OverflowDemo {
public static void main(String[] args) {
List<byte[]> leakList = new ArrayList<>();
while (true) {
// 持续申请1MB内存却不释放
leakList.add(new byte[1024 * 1024]);
}
}
}
/* 运行结果:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
*/
二、为什么会溢出?
2.1 内存泄漏(举着水杯不放手)
就像借书不还导致图书馆没书可借,某些对象已经不用了,却被意外保留引用无法回收。比如:
// 技术栈:Java 8
public class LeakExample {
static Map<Long, Object> cache = new HashMap<>();
public void addToCache(long id) {
// 缓存对象但忘记设置淘汰机制
cache.put(id, new byte[1024 * 1024]);
}
}
/* 随着时间推移,cache会吃掉所有堆内存 */
2.2 配置不足(杯子太小)
新生代和老年代比例不合理,比如电商大促时:
// 启动参数配置不当示例
-Xms128m -Xmx128m // 只给128MB堆内存
// 实际需要处理10万订单数据时:
List<Order> orders = queryAllOrders(); // 瞬间爆炸
三、实战排查四步走
3.1 收集证据(拍下案发现场)
用JDK自带工具快速取证:
# 查看内存概况
jmap -heap <pid>
# 生成堆转储文件
jmap -dump:format=b,file=heap.hprof <pid>
3.2 分析线索(侦探时间)
使用MAT工具分析hprof文件,重点关注:
- 占用空间最大的对象(按Size排序)
- 对象引用链(Path to GC Roots)
3.3 修复方案
案例1:线程池未关闭
// 错误示范:线程池用完没shutdown
ExecutorService pool = Executors.newFixedThreadPool(5);
pool.submit(() -> { /* 耗时任务 */ });
// 正确做法:添加钩子关闭
Runtime.getRuntime().addShutdownHook(
new Thread(pool::shutdownNow)
);
案例2:缓存失控
// 使用WeakHashMap自动清理
Map<Key, BigObject> cache =
Collections.synchronizedMap(new WeakHashMap<>());
// 或者用Guava Cache设置上限
Cache<Key, Value> cache = CacheBuilder.newBuilder()
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.build();
四、防患于未然
4.1 合理配置参数
根据应用特点调整:
# 电商类应用建议
-Xms4g -Xmx4g -XX:NewRatio=2
-XX:+UseG1GC -XX:MaxGCPauseMillis=200
4.2 监控预警
Spring Boot Actuator配置示例:
management:
endpoints:
web:
exposure:
include: health,metrics
metrics:
tags:
application: ${spring.application.name}
4.3 代码规范
避免常见陷阱:
- 慎用静态集合
- 及时关闭IO流
- 大数据集分批次处理
五、特别场景处理
5.1 堆外内存溢出
报错特征:OutOfMemoryError: Direct buffer memory
解决方案:
// 调整MaxDirectMemorySize
-XX:MaxDirectMemorySize=256m
// 显式回收ByteBuffer
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
((DirectBuffer) buffer).cleaner().clean();
5.2 元空间溢出
报错特征:OutOfMemoryError: Metaspace
动态加载类场景需注意:
# 调整元空间大小
-XX:MetaspaceSize=128m
-XX:MaxMetaspaceSize=256m
六、总结与避坑指南
应用场景:高并发系统、长时间运行服务、大数据处理
技术优劣:
- 优点:工具链成熟,大部分问题可定位
- 缺点:某些内存泄漏需要长期监控才能发现
注意事项:
- 生产环境慎用
-XX:+HeapDumpOnOutOfMemoryError - 堆转储文件可能很大(建议单独磁盘存储)
- 容器化部署时注意cgroup内存限制
记住三原则:
- 给内存设合理上限
- 像管理钱包一样管理对象引用
- 重要系统添加内存水位监控
评论