实战OutOfMemoryError异常
这些异常你是否遇到过?正式开讲之前 , 先罗列一下所知的 OutOfMemoryError (简称 OOM)异常 , 看看这些异常工作中你是否也遇到过?
Java 堆内存溢出:java.lang.OutOfMemoryError: Java heap space
垃圾回收内存溢出:java.lang.OutOfMemoryError: GC overhead limit exceeded
方法区溢出:java.lang.OutOfMemoryError: PermGen space
Metaspace 内存溢出:java.lang.OutOfMemoryError: Metaspace
直接内存内存溢出:java.lang.OutOfMemoryError: Direct buffer memory
栈内存溢出:java.lang.StackOverflowError
创建本地线程内存溢出:java.lang.OutOfMemoryError: Unable to create new native thread
数组超限内存溢出:java.lang.OutOfMemoryError:Requested array size exceeds VM limit
在实际工作中 , 若真遇到了上面罗列的这些内存溢出的异常 , 你是否能够根据异常提示迅速定位是哪儿出了幺蛾子 , 并是否能够铲除这些幺蛾子呢?
希望通过此篇分享 , 尽量能够让大家了解每个异常发生的场景 , 并能够掌握每个异常场景的应对之策 。
文章插图
如上图示意 , 按照内存共享来划分 JVM 内存 , 主要划分为线程共享内存区域(堆、方法区)、线程私有内存区域(程序计数器、虚拟机栈、本地方法栈)、直接内存 。 而在《Java 虚拟机规范》的规定里 , 除了程序计数器外 , 虚拟机内存的其它几个运行时区域都可能发生 OOM 异常 , 接下来通过代码来剖析一下各种 OutOfMemoryError(OOM)的场景 。
实战:OutOfMemoryError 异常场景一
java.lang.OutOfMemoryError: Java heap space
/** * VM options:-Xms10m -Xmx10m -XX:+HeapDumpOnOutOfMemoryError * @author 一猿小讲 */public class HeapOOM {public static void main(String[] args) {byte[] bytes = new byte[20 * 1024 * 1024];System.out.println(bytes);}}
理论且不谈 , 直接抛代码 , 代码很简单 , 创建一个字节数组对象 , 要分配 20M 的空间 。 若在运行程序时指定 VM 参数:
- 通过参数 -Xms10m -Xmx10m 将堆的最小值与最大值都设置为 10M , 即限制 Java 堆的大小为 10MB , 并且避免堆自动扩展;
- 通过参数 -XX:+HeapDumpOnOutOf-MemoryError 让虚拟机在出现内存溢出异常的时候 Dump 出当前的内存堆转储快照以便进行事后分析 。
java.lang.OutOfMemoryError: Java heap spaceDumping heap to java_pid35115.hprof ...Heap dump file created [1033561 bytes in 0.005 secs]Exception in thread "main" java.lang.OutOfMemoryError: Java heap spaceat HeapOOM.main(HeapOOM.java:7)
为什么呢?简单解释原因 , -Xms10m -Xmx10m 限制了堆的最大值为 10M , 而 new byte[20 * 1024 * 1024] 需要 20M 的空间 , 则堆内存明显不够 , 则直接导致 OOM 。面对此种异常 , 常规解决思路:
- 要检查一下代码是否存在优化的空间;
- 依据内存溢出时的快照文件 xx.hprof 来判断是否存在内存泄露 , 不需要的对象有没有被回收掉;
- 调节虚拟机的堆参数(-Xms -Xmx) , 适当调大堆内存 。
java.lang.OutOfMemoryError: GC overhead limit exceeded
/** * VM options:-Xmx6m -XX:+HeapDumpOnOutOfMemoryError * @author 一猿小讲 */public class HeapOOM {static class GirlFriend {}public static void main(String[] args) {List list = new ArrayList();while (true) {list.add(new GirlFriend());}}}
理论且不谈 , 直接抛代码 , 代码很简单 , 一直往集合中加入新创建的对象(虚妄的单身狗生活:一直创建女朋友对象 。 )若在运行程序时指定 VM 参数:
- 通过参数 -Xmx6m 将堆的最大值设置为 6M;
- 通过参数 -XX:+HeapDumpOnOutOf-MemoryError 让虚拟机在出现内存溢出异常的时候 Dump 出当前的内存堆转储快照以便进行事后分析 。
java.lang.OutOfMemoryError: GC overhead limit exceededDumping heap to java_pid35304.hprof ...Heap dump file created [12557270 bytes in 0.082 secs]Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceededat HeapOOM.main(HeapOOM.java:16)
为什么呢?来段洋文 , 尝试解读一下 。The parallel(concurrent) collector will throw an OutOfMemoryError if too much time is being spent in garbage collection: if more than 98% of the total time is spent in garbage collection and less than 2% of the heap is recovered, an OutOfMemoryError will be thrown.
大概意思应用程序在垃圾收集上花费了太多时间 , 但是却没有什么卵用 , 默认超过 98% 的时间用来做GC却回收了不到2%的内存时将会抛出 OutOfMemoryError 异常 。
面对此种异常 , 常规解决思路:
- Wireshark数据包分析实战:TCP报文段重组
- Python爬虫采集网易云音乐热评实战
- Django实战016:django中使用redis详解
- HTTP实战之Wireshark抓包分析
- Wireshark数据包分析实战:网卡卸载
- 「8」进大厂必须掌握的面试题-Java面试-异常和线程
- Python数据分析:数据可视化实战教程
- 实战经验:电商平台遭遇CC攻击,我们是如何应对的?
- Tencent IN对话 | 八位互联网实战家,实战智慧营销商学院
- HLS实战之Wireshark抓包分析