list.add(newObject);
}
解决方案:
检查内存泄漏(使用 jmap+ MAT分析堆转储)。
调整堆大小(-Xmx和 -Xms)。
优化代码逻辑,减少对象生命周期。
检查内存泄漏(使用 jmap+ MAT分析堆转储)。
调整堆大小(-Xmx和 -Xms)。
优化代码逻辑,减少对象生命周期。
触发原因:元空间(Metaspace)或永久代(PermGen)内存不足,用于存储类元数据、方法信息等。
典型场景:
动态生成大量类(如使用 CGLib、反射、动态代理)。
类加载器未正确释放(如频繁部署的 Web 应用导致旧类未卸载)。
触发原因:元空间(Metaspace)或永久代(PermGen)内存不足,用于存储类元数据、方法信息等。
典型场景:
动态生成大量类(如使用 CGLib、反射、动态代理)。
类加载器未正确释放(如频繁部署的 Web 应用导致旧类未卸载)。
动态生成大量类(如使用 CGLib、反射、动态代理)。
类加载器未正确释放(如频繁部署的 Web 应用导致旧类未卸载)。
示例:
// 使用 CGLib 动态生成大量代理类
Enhancer enhancer = newEnhancer;
while(true) {
enhancer.setSuperclass(OOM.class);
enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) -> proxy.invokeSuper(obj, args)));
enhancer.create;
}
解决方案:
调整元空间大小(-XX:MaxMetaspaceSize)。
检查类加载器泄漏或动态类生成逻辑。
调整元空间大小(-XX:MaxMetaspaceSize)。
检查类加载器泄漏或动态类生成逻辑。
触发原因:直接内存(Direct Memory,通过 ByteBuffer.allocateDirect分配)耗尽。
典型场景:
频繁申请直接内存但未及时释放(需依赖 System.gc或 Cleaner机制)。
JVM 直接内存参数(-XX:MaxDirectMemorySize)设置过小。
触发原因:直接内存(Direct Memory,通过 ByteBuffer.allocateDirect分配)耗尽。
典型场景:
频繁申请直接内存但未及时释放(需依赖 System.gc或 Cleaner机制)。
JVM 直接内存参数(-XX:MaxDirectMemorySize)设置过小。
频繁申请直接内存但未及时释放(需依赖 System.gc或 Cleaner机制)。
JVM 直接内存参数(-XX:MaxDirectMemorySize)设置过小。
示例:
// 不断申请直接内存
List
while(true) {
buffers.add(ByteBuffer.allocateDirect(1024* 1024)); // 1MB
}
解决方案:
检查直接内存使用代码,确保及时释放。
调整 -XX:MaxDirectMemorySize。
检查直接内存使用代码,确保及时释放。
调整 -XX:MaxDirectMemorySize。
触发原因:操作系统限制线程数量,无法创建新线程。
典型场景:
线程数超过系统限制(如 Linux 的 ulimit -u)。
每个线程的栈内存(-Xss)设置过大,导致总内存占用超出。
触发原因:操作系统限制线程数量,无法创建新线程。
典型场景:
线程数超过系统限制(如 Linux 的 ulimit -u)。
每个线程的栈内存(-Xss)设置过大,导致总内存占用超出。
线程数超过系统限制(如 Linux 的 ulimit -u)。
每个线程的栈内存(-Xss)设置过大,导致总内存占用超出。
示例:
// 无限创建线程
while(true) {
newThread( -> {
}).start;
}
解决方案:
减少线程数(使用线程池)。
调整 -Xss减小线程栈大小。
修改系统线程数限制。
减少线程数(使用线程池)。
调整 -Xss减小线程栈大小。
修改系统线程数限制。
触发原因:尝试分配超过 JVM 限制的数组(通常接近 Integer.MAX_VALUE)。
典型场景:错误计算数组长度,如 new int[Integer.MAX_VALUE]。
触发原因:尝试分配超过 JVM 限制的数组(通常接近 Integer.MAX_VALUE)。
典型场景:错误计算数组长度,如 new int[Integer.MAX_VALUE]。
解决方案:
检查数组长度计算逻辑,使用合理的数据结构。
检查数组长度计算逻辑,使用合理的数据结构。
触发原因:GC 频繁执行但回收效率极低(如 98% 时间用于 GC,仅回收 2% 内存)。
典型场景:堆内存几乎被占满,且存在大量无法回收的对象(内存泄漏)。
触发原因:GC 频繁执行但回收效率极低(如 98% 时间用于 GC,仅回收 2% 内存)。
典型场景:堆内存几乎被占满,且存在大量无法回收的对象(内存泄漏)。
解决方案:
检查内存泄漏或优化 GC 策略(如调整堆大小、更换垃圾回收器)。
检查内存泄漏或优化 GC 策略(如调整堆大小、更换垃圾回收器)。
触发原因:JIT 编译器生成的本地代码占满代码缓存区。
典型场景:高频动态编译大量方法(如复杂的热点代码)。
触发原因:JIT 编译器生成的本地代码占满代码缓存区。
典型场景:高频动态编译大量方法(如复杂的热点代码)。
解决方案:
调整代码缓存大小(-XX:ReservedCodeCacheSize)。
关闭分层编译(-XX:-TieredCompilation)。
调整代码缓存大小(-XX:ReservedCodeCacheSize)。
关闭分层编译(-XX:-TieredCompilation)。
OOM 的根本原因是 JVM 内存区域不足或 资源耗尽,需结合错误类型分析具体内存区域(堆、元空间、直接内存等)。
排查时可通过以下步骤:
1、确定 OOM 类型(通过错误日志)。
2、使用工具分析(如 jstat、jmap、VisualVM、MAT)。
3、调整 JVM 参数或优化代码逻辑。返回搜狐,查看更多