PDF大白话说Java面试题 — 02-JVM篇第25题谈谈对 OOM 的认识回答核心考点OOMOutOfMemoryError是JVM内存耗尽的终极表现。大厂面试要求能区分不同内存区域的OOM、常见原因、排查手段以及为什么OOM后程序不一定立即退出。1. OOM 的完整分类按区域OOM类型错误信息对应内存区域典型场景堆内存溢出Java heap space堆Heap内存泄漏、对象峰值过大元空间溢出Metaspace元空间Metaspace动态类加载热部署、CGlib代理GC超限GC overhead limit exceeded堆98%时间GC但回收不到2%内存直接内存溢出Direct buffer memory直接内存Direct MemoryNIO/BIO中ByteBuffer.allocateDirect泄漏无法创建本地线程unable to create new native thread栈Native Thread线程数超系统上限栈溢出不同概念StackOverflowError虚拟机栈递归过深注意StackOverflowError虽然是内存耗尽但不属于OOM而是单独的错误。但面试常混问。2. 堆内存溢出最常见触发条件新对象分配时堆内存已满 GC回收后仍不足。代码示例生产常见Listbyte[]listnewArrayList();while(true){list.add(newbyte[1024*1024]);// 1MB}根因分类内存泄漏对象意外被强引用无法回收如HashMap未remove、静态集合缓存无清理内存峰值请求处理时创建大对象如批量导入Excel排查命令-XX:HeapDumpOnOutOfMemoryError-XX:HeapDumpPath/data/dump.hprof3. 元空间溢出触发条件加载的新类超过-XX:MaxMetaspaceSize限制。高危场景热部署Spring DevTools、Tomcat reload每次部署加载新ClassLoader旧类未卸载动态代理CGLIB或Javassist生成大量代理类如Spring中Configuration类JSP旧项目每个JSP编译成单独的类验证方式jstat-gcPID|grep-EM|Metaspace# M (Metaspace) 使用率持续增长直到触发FGC4. GC overhead limit exceeded错误信息java.lang.OutOfMemoryError: GC overhead limit exceeded触发条件JVM检测到GC时间 98%且回收内存 2%持续多次后抛出。防止系统因无效GC彻底卡死。典型场景堆内存接近满但每次GC只能回收极少量对象通常是堆太小或存在大量临时对象解决不推荐关闭此检测-XX:-UseGCOverheadLimit应增大堆或排查泄漏5. 直接内存溢出错误信息java.lang.OutOfMemoryError: Direct buffer memory触发条件ByteBuffer.allocateDirect()分配的堆外内存超过-XX:MaxDirectMemorySize默认等于-Xmx。常见原因NIO框架Netty、Jetty未及时释放DirectByteBuffer使用ThreadLocal缓存DirectBuffer导致泄漏排查# 查看直接内存使用量需jdk8u40jdk/bin/jcmdPIDVM.native_memory summary6. 无法创建本地线程错误信息java.lang.OutOfMemoryError: unable to create new native thread触发条件系统总线程数超上限Linux通常受/proc/sys/kernel/threads-max或内存限制。根因显式创建海量线程如线程池无限增长每个线程栈-Xss占用内存过大导致即使线程数不多也会触发公式最大线程数 ≈ (进程最大内存 - 堆 - 元空间) / (-Xss)7. OOM排查标准流程大厂必问步骤操作工具/参数1. 保留现场启动时加-XX:HeapDumpOnOutOfMemoryError自动dump2. 获取dump文件从-XX:HeapDumpPath路径找到.hprofMAT / VisualVM / JProfiler3. 分析泄漏对象查看Dominator Tree、Leak SuspectsMAT自动报告4. 定位代码行分析GC Roots到泄漏对象的最短路径OQL查询5. 复现与修复压测验证JMeter等无dump时的现场信息jstat-gcutilPID1000# 看各区域使用率jmap-histo:livePID# 存活对象统计会STW慎用8. OOM后程序一定会退出吗答不一定。如果OOM发生在非主线程如线程池任务内该线程抛出OutOfMemoryError后终止但其他线程包括主线程可能继续运行。危险OOM后系统状态不一致继续处理请求可能导致数据损坏。生产最佳实践-XX:OnOutOfMemoryErrorkill -9 %p# OOM时直接杀进程或通过健康检查如k8s liveness probe自动重启。9. 面试官追问示例与回答Q1Java heap space和GC overhead limit exceeded什么区别A前者是堆满且GC后仍无空间分配新对象后者是GC一直在工作但无效98%时间GC回收2%内存属于JVM的保护机制。Q2元空间溢出只加MaxMetaspaceSize就能解决吗A治标不治本。应排查是否存在类加载器泄漏如Tomcat热部署后原ClassLoader未卸载结合jmap -clstats查看类加载器数量。Q3直接内存溢出如何定位A用jcmd PID VM.native_memory summary看Internal区域或使用-XX:NativeMemoryTrackingdetail跟踪。Netty可开启leakDetectionLevel。Q4OOM后还能执行finally块吗AOOM是Errorfinally会执行如果OOM发生在try内部。但若OOM发生在finally内部则不会执行完。面试官想要的满分总结“OOM按区域分为堆、元空间、直接内存、本地线程等类型。必须开启-XX:HeapDumpOnOutOfMemoryError保留现场。排查路径dump → MAT分析Leak Suspects → 定位GC Roots → 修复引用链。注意非主线程的OOM不会导致进程退出需通过-XX:OnOutOfMemoryErrorkill -9 %p确保快速自愈。常见误区StackOverflowError不是OOMGC overhead limit exceeded也是OOM的一种元空间溢出常与类加载器泄漏有关而非单纯空间太小。”觉得对您有帮助麻烦点点关注啦您的关注是我创作的最大动力~
【大白话说Java面试题 第6x题】【JVM篇】第25题:谈谈对 OOM 的认识
PDF大白话说Java面试题 — 02-JVM篇第25题谈谈对 OOM 的认识回答核心考点OOMOutOfMemoryError是JVM内存耗尽的终极表现。大厂面试要求能区分不同内存区域的OOM、常见原因、排查手段以及为什么OOM后程序不一定立即退出。1. OOM 的完整分类按区域OOM类型错误信息对应内存区域典型场景堆内存溢出Java heap space堆Heap内存泄漏、对象峰值过大元空间溢出Metaspace元空间Metaspace动态类加载热部署、CGlib代理GC超限GC overhead limit exceeded堆98%时间GC但回收不到2%内存直接内存溢出Direct buffer memory直接内存Direct MemoryNIO/BIO中ByteBuffer.allocateDirect泄漏无法创建本地线程unable to create new native thread栈Native Thread线程数超系统上限栈溢出不同概念StackOverflowError虚拟机栈递归过深注意StackOverflowError虽然是内存耗尽但不属于OOM而是单独的错误。但面试常混问。2. 堆内存溢出最常见触发条件新对象分配时堆内存已满 GC回收后仍不足。代码示例生产常见Listbyte[]listnewArrayList();while(true){list.add(newbyte[1024*1024]);// 1MB}根因分类内存泄漏对象意外被强引用无法回收如HashMap未remove、静态集合缓存无清理内存峰值请求处理时创建大对象如批量导入Excel排查命令-XX:HeapDumpOnOutOfMemoryError-XX:HeapDumpPath/data/dump.hprof3. 元空间溢出触发条件加载的新类超过-XX:MaxMetaspaceSize限制。高危场景热部署Spring DevTools、Tomcat reload每次部署加载新ClassLoader旧类未卸载动态代理CGLIB或Javassist生成大量代理类如Spring中Configuration类JSP旧项目每个JSP编译成单独的类验证方式jstat-gcPID|grep-EM|Metaspace# M (Metaspace) 使用率持续增长直到触发FGC4. GC overhead limit exceeded错误信息java.lang.OutOfMemoryError: GC overhead limit exceeded触发条件JVM检测到GC时间 98%且回收内存 2%持续多次后抛出。防止系统因无效GC彻底卡死。典型场景堆内存接近满但每次GC只能回收极少量对象通常是堆太小或存在大量临时对象解决不推荐关闭此检测-XX:-UseGCOverheadLimit应增大堆或排查泄漏5. 直接内存溢出错误信息java.lang.OutOfMemoryError: Direct buffer memory触发条件ByteBuffer.allocateDirect()分配的堆外内存超过-XX:MaxDirectMemorySize默认等于-Xmx。常见原因NIO框架Netty、Jetty未及时释放DirectByteBuffer使用ThreadLocal缓存DirectBuffer导致泄漏排查# 查看直接内存使用量需jdk8u40jdk/bin/jcmdPIDVM.native_memory summary6. 无法创建本地线程错误信息java.lang.OutOfMemoryError: unable to create new native thread触发条件系统总线程数超上限Linux通常受/proc/sys/kernel/threads-max或内存限制。根因显式创建海量线程如线程池无限增长每个线程栈-Xss占用内存过大导致即使线程数不多也会触发公式最大线程数 ≈ (进程最大内存 - 堆 - 元空间) / (-Xss)7. OOM排查标准流程大厂必问步骤操作工具/参数1. 保留现场启动时加-XX:HeapDumpOnOutOfMemoryError自动dump2. 获取dump文件从-XX:HeapDumpPath路径找到.hprofMAT / VisualVM / JProfiler3. 分析泄漏对象查看Dominator Tree、Leak SuspectsMAT自动报告4. 定位代码行分析GC Roots到泄漏对象的最短路径OQL查询5. 复现与修复压测验证JMeter等无dump时的现场信息jstat-gcutilPID1000# 看各区域使用率jmap-histo:livePID# 存活对象统计会STW慎用8. OOM后程序一定会退出吗答不一定。如果OOM发生在非主线程如线程池任务内该线程抛出OutOfMemoryError后终止但其他线程包括主线程可能继续运行。危险OOM后系统状态不一致继续处理请求可能导致数据损坏。生产最佳实践-XX:OnOutOfMemoryErrorkill -9 %p# OOM时直接杀进程或通过健康检查如k8s liveness probe自动重启。9. 面试官追问示例与回答Q1Java heap space和GC overhead limit exceeded什么区别A前者是堆满且GC后仍无空间分配新对象后者是GC一直在工作但无效98%时间GC回收2%内存属于JVM的保护机制。Q2元空间溢出只加MaxMetaspaceSize就能解决吗A治标不治本。应排查是否存在类加载器泄漏如Tomcat热部署后原ClassLoader未卸载结合jmap -clstats查看类加载器数量。Q3直接内存溢出如何定位A用jcmd PID VM.native_memory summary看Internal区域或使用-XX:NativeMemoryTrackingdetail跟踪。Netty可开启leakDetectionLevel。Q4OOM后还能执行finally块吗AOOM是Errorfinally会执行如果OOM发生在try内部。但若OOM发生在finally内部则不会执行完。面试官想要的满分总结“OOM按区域分为堆、元空间、直接内存、本地线程等类型。必须开启-XX:HeapDumpOnOutOfMemoryError保留现场。排查路径dump → MAT分析Leak Suspects → 定位GC Roots → 修复引用链。注意非主线程的OOM不会导致进程退出需通过-XX:OnOutOfMemoryErrorkill -9 %p确保快速自愈。常见误区StackOverflowError不是OOMGC overhead limit exceeded也是OOM的一种元空间溢出常与类加载器泄漏有关而非单纯空间太小。”觉得对您有帮助麻烦点点关注啦您的关注是我创作的最大动力~