五金东莞网站建设技术支持,基于WordPress免费博客,怎么用手机做软件,绵竹网站建设针对目前大家对OOM的类型不太熟悉#xff0c;那么来总结一下各种OOM出现的情况以及解决方法。把各种OOM的情况列出来#xff0c;然后逐一进行代码编写复现和提供解决方法。1. 堆溢出-java.lang.OutOfMemoryError: Java heap space。2. 栈溢出-java.lang.OutOfMemorryError。3…针对目前大家对OOM的类型不太熟悉那么来总结一下各种OOM出现的情况以及解决方法。把各种OOM的情况列出来然后逐一进行代码编写复现和提供解决方法。1. 堆溢出-java.lang.OutOfMemoryError: Java heap space。2. 栈溢出-java.lang.OutOfMemorryError。3. 栈溢出-java.lang.StackOverFlowError。4. 元信息溢出-java.lang.OutOfMemoryError: Metaspace。5. 直接内存溢出-java.lang.OutOfMemoryError: Direct buffer memory。6. GC超限-java.lang.OutOfMemoryError: GC overhead limit exceeded。0x01: 堆溢出异常相信大家很常见。即堆内对象不能进行回收了堆内存持续增大这样达到了堆内存的最大值数据满了所以就出来了。我们直接放溢出的代码样例。需要设置好idea的VM Options: -Xmx100m这样设置为最大堆内存这样运行起来就很快就出来错误了。package oom;import java.util.ArrayList;import java.util.List;import java.util.concurrent.TimeUnit;public class HeapOOM { static class OOMObject { } public static void main(String[] args) throws InterruptedException { List list new ArrayList(); while(true) {// TimeUnit.MILLISECONDS.sleep(1); list.add(new OOMObject()); } }}运行的异常如下代码直接就出来我们看到的异常了。/Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home/bin/java -Xmx100mException in thread main java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOf(Arrays.java:3210) at java.util.Arrays.copyOf(Arrays.java:3181) at java.util.ArrayList.grow(ArrayList.java:261) at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235) at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227) at java.util.ArrayList.add(ArrayList.java:458) at oom.HeapOOM.main(HeapOOM.java:21)Process finished with exit code 1细心的小伙伴可以发现代码中设置了一个休眠目的是看一下堆内存的结构和数据图。将休眠代码打开然后打开JDK自带的jconsole命令连接上之后看一下概览图通过下图发现堆内存持续不断的增长。 打开内存界面看一下内存然后点一下GC按钮这个时候会有一些类进行回收但是还是会继续增长看一下下面的图。点开信息标签看一下。经过几次GC回收之后类的数据量还是变化不大说明没有进行回收。以上这种情况的解决方法就是找到问题点分析哪个地方是否存储了大量类没有被回收的情况通过JMAP命令将线上的堆内存导出来后进行分析。0x02: 看一下栈溢出的情况下面的代码就是无限的创建线程直到没法再创建线程。package oom;import java.util.concurrent.TimeUnit;/** * Date 2020-07-18 */public class StackOOM { public static void infiniteRun() { while(true) { Thread thread new Thread(() - { while (true) { try { TimeUnit.HOURS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } }); thread.start(); } } public static void main(String[] args) { infiniteRun(); }}抛出来的异常如下如果真的需要创建线程我们需要调整帧栈的大小-Xss512k默认帧栈大小为1M如果设置小了可以创建更多线程。/Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home/bin/java -Xss512k Exception in thread main java.lang.OutOfMemoryError: unable to create new native thread at java.lang.Thread.start0(Native Method) at java.lang.Thread.start(Thread.java:717) at oom.StackOOM.infiniteRun(StackOOM.java:24) at oom.StackOOM.main(StackOOM.java:29)Process finished with exit code 130 (interrupted by signal 2: SIGINT)以上这种情况是帧栈不够用了如果出现了这种情况需要了解什么地方创建了很多线程线上程序需要用jstack命令将当前线程的状态导出来放到文件里边然后将文件上传到fastthread.io网站上进行分析。0x03看一下栈溢出的另一种情况这就是栈的StackOverFlow的情况。下面就是一个死循环递归调用。package oom;/** * Date 2020-07-18 */public class StackOFE { public static void stackOverFlowErrorMethod() { stackOverFlowErrorMethod(); } public static void main(String[] args) { stackOverFlowErrorMethod(); }}运行之后出现的错误如下程序每次递归的时候程序会把数据结果压入栈包括里边的指针等这个时候就需要帧栈大一些才能承受住更多的递归调用。通过-Xss进行设置上边的例子需要设置小一些以分配更多的帧栈这次是一个帧栈需要记录程序数据所以需要更大的值。/Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home/bin/java -Xss2mException in thread main java.lang.StackOverflowError at oom.StackOFE.stackOverFlowErrorMethod(StackOFE.java:10) at oom.StackOFE.stackOverFlowErrorMethod(StackOFE.java:10) at oom.StackOFE.stackOverFlowErrorMethod(StackOFE.java:10) at oom.StackOFE.stackOverFlowErrorMethod(StackOFE.java:10) at oom.StackOFE.stackOverFlowErrorMethod(StackOFE.java:10) at oom.StackOFE.stackOverFlowErrorMethod(StackOFE.java:10)遇到上面的情况下那么就需要通过jstack将线程数据导到文件进行分析。找到递归的点如果程序就是需要递归的次数的话那么这个时候就需要增大帧栈的大小以适应程序。0x04: 元数据区域溢出元数据区域也成为方法区存储着类的相关信息常量池方法描述符字段描述符运行时产生大量的类就会造成这个区域的溢出。我们运行的时候指定一下元数据区域的大小设置到idea的VM options里边-XX:MetaspaceSize10M -XX:MaxMetaspaceSize30M。package oom;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;/** * Date 2020-07-18 */public class MetaspaceOOM { static class OOMObject{} public static void main(String[] args) { while (true) { Enhancer enhancer new Enhancer(); enhancer.setSuperclass(OOMObject.class); enhancer.setUseCache(false); enhancer.setCallback(new MethodInterceptor() { public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { return proxy.invokeSuper(obj, args); } }); enhancer.create(); } }}运行的结果如下元数据信息溢出了。这种情况产生的原因有通过CBLIG大量生成类导致Meta信息满了JDK7的时候使用String.intern()不当会产生大量常量数据加载大量的jsp以及动态生成jsp文件。需要调整元数据空间的大小如果调大了之后还出现了这种异常我们需要分析哪里出现的溢出并fix掉。/Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home/bin/java -XX:MetaspaceSizeException in thread main java.lang.OutOfMemoryError: Metaspace at net.sf.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:345) at net.sf.cglib.proxy.Enhancer.generate(Enhancer.java:492) at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:114) at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:291) at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:480) at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:305) at oom.MetaspaceOOM.main(MetaspaceOOM.java:28)Process finished with exit code 10x05: 直接内存溢出除了使用堆内存外还可能用直接内存即堆外内存。NIO为了提高性能避免在Java Heap和native Heap中切换所以使用直接内存默认情况下直接内存的大小和对内存大小一致。堆外内存不受JVM的限制但是受制于机器整体内存的大小限制。如下代码设置堆最大内存为128m直接内存为100m然后我们每次分配1M放到list里边。 -Xmx128m -XX:MaxDirectMemorySize100Mpackage oom;import java.nio.ByteBuffer;import java.util.ArrayList;import java.util.List;/** * Date 2020-07-18 */public class DirectBufferOOM { public static void main(String[] args) { final int _1M 1024 * 1024 * 1; List buffers new ArrayList(); int count 1; while (true) { ByteBuffer byteBuffer ByteBuffer.allocateDirect(_1M); buffers.add(byteBuffer); System.out.println(count); } }}这个时候当输出100次的时候下次再分配的时候会报OOM-Direct buffer memory。/Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home/bin/java -Xmx128m Exception in thread main java.lang.OutOfMemoryError: Direct buffer memory at java.nio.Bits.reserveMemory(Bits.java:694) at java.nio.DirectByteBuffer.(DirectByteBuffer.java:123) at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:311) at oom.DirectBufferOOM.main(DirectBufferOOM.java:18)Process finished with exit code 1这种情况是我们使用直接内存造成溢出这个时候我们需要检查一下程序里边是否使用的NIO及NIO比如Netty里边的直接内存的配置。0x06: JDK1.6之后新增了一个错误类型如果堆内存太小的时候会报这个错误。如果98%的GC的时候回收不到2%的时候会报这个错误也就是最小最大内存出现了问题的时候会报这个错误。如果代码配置了最小最大堆内存都为10m。-Xmx10m -Xms10mpackage oom;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/** * Date 2020-07-18 */public class GCOverheadOOM { public static void main(String[] args) { ExecutorService executor Executors.newFixedThreadPool(5); for (int i 0; i { try { Thread.sleep(10000); } catch (InterruptedException e) { //do nothing } }); } }}这个创建了一个线程池如果线程池执行的时候如果核心线程处理不过来的时候会把数据放到LinkedBlockingQueue里边也就是堆内存当中。这个时候我们需要检查-Xms -Xmx最小最大堆配置是否合理。再一个dump出现当前内存来分析一下是否使用了大量的循环或使用大量内存代码。以上就是经常遇到的情况需要针对出现的不同情况进行分析和处理。