Java开发中或者部署到服务器上后,可能经常发生内存溢出,本文总结下常见的溢出情况。
内存溢出的原因
Java内存溢出的原因:程序在申请内存时,没有足够的内存空间
.
内存溢出有几种类型,如下:
栈溢出
栈溢出的第1种情况,死递归,抛出StackOverflowError
如下代码:
public class StackOverFlow { public void test(){ test();//死递归 } public static void main(String[] args)throws Throwable { StackOverFlow javaStack = new StackOverFlow(); javaStack.test(); } }
运行后发生如下异常:
Exception in thread “main” java.lang.StackOverflowError
at com.jvm.ch05.oom.StackOverFlow.test(StackOverFlow.java:13)
at com.jvm.ch05.oom.StackOverFlow.test(StackOverFlow.java:13)
在java虚拟机种,Java的栈空间默认是1M大小(可以通过-Xss调整,一般不用调整
),反复调用,会超出栈溢出。
栈溢出的第2种情况,线程太多,抛出OutOfMemoryError
如果1个方法运行中的对象占用1M内存。同时5000+个线程运行这个方法,如果机器的内存小于5G的话,那么也会发生内存溢出,这种情况会抛出OOM异常。
堆溢出
1.初始对象太大,超过机器内存,抛出OutOfMemoryError: Java heap space
如下代码:
//VM Args:-Xms30m -Xmx30m -XX:+PrintGCDetails 堆的大小30M String[] strings = new String[100000000]; //100m的数组(堆)
运行结果:
Exception in thread “main” java.lang.OutOfMemoryError: Java heap space
at com.jvm.ch05.oom.HeapOom.main(HeapOom.java:14)
对象分配内存需要100M.如果机器的内存小于100M就会发生 Java heap space。
2.在方法执行中,回收效率不足2%,抛出OutOfMemoryError: GC overhead limit exceeded
demo如下:
/** * * VM Args:-Xms10m -Xmx10m -Xmn5m -XX:+PrintGCDetails 堆的大小10M * 堆内存溢出 */ public class HeapOom { public static void main(String[] args) { List<Object> list = new LinkedList<>(); //在方法执行的过程中,它是GCRoots int i =0; while(true){ i++; if(i%10000==0) System.out.println("i="+i); list.add(new Object()); } } }
运行结果:
[Full GC (Ergonomics) [PSYoungGen: 4096K->4096K(4608K)] [ParOldGen: 5045K->5045K(5120K)] 9141K->9141K(9728K), [Metaspace: 3356K->3356K(1056768K)], 0.1506820 secs] [Times: user=1.05 sys=0.00, real=0.15 secs]
[Full GC (Ergonomics) [PSYoungGen: 4096K->4096K(4608K)] [ParOldGen: 5047K->5047K(5120K)] 9143K->9143K(9728K), [Metaspace: 3356K->3356K(1056768K)], 0.1767119 secs] [Times: user=1.11 sys=0.00, real=0.18 secs]
[Full GC (Ergonomics) [PSYoungGen: 4096K->4096K(4608K)] [ParOldGen: 5048K->5048K(5120K)] 9144K->9144K(9728K), [Metaspace: 3356K->3356K(1056768K)], 0.1575503 secs] [Times: user=0.99 sys=0.00, real=0.16 secs]
[Full GC (Ergonomics) [PSYoungGen: 4096K->0K(4608K)] [ParOldGen: 5052K->658K(5120K)] 9148K->658K(9728K), [Metaspace: 3356K->3356K(1056768K)], 0.0188752 secs] [Times: user=0.09 sys=0.00, real=0.02 secs]
Heap
PSYoungGen total 4608K, used 169K [0x00000000ffb00000, 0x0000000100000000, 0x0000000100000000)
eden space 4096K, 4% used [0x00000000ffb00000,0x00000000ffb2a498,0x00000000fff00000)
from space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
to space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
ParOldGen total 5120K, used 658K [0x00000000ff600000, 0x00000000ffb00000, 0x00000000ffb00000)
object space 5120K, 12% used [0x00000000ff600000,0x00000000ff6a4b48,0x00000000ffb00000)
Metaspace used 3390K, capacity 4500K, committed 4864K, reserved 1056768K
class space used 364K, capacity 388K, committed 512K, reserved 1048576K
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
at com.jvm.ch05.oom.HeapOom.main(HeapOom.java:20)
原因: 本例中一直在发生fullgc中,list集合一直在塞入对象,回收内存占比越来越小,虚拟机中有个规则:垃圾回收(线程)占用超过了98%的资源,但是回收效率不足2%,就会发生了’OOM, GC overhead limit exceeded
。
直接内存溢出 Direct buffer memory
分配的本地内存大小大于JVM的限制.
demo如下:
设置参数: -XX:MaxDirectMemorySize=100m
/** * VM Args:-XX:MaxDirectMemorySize=100m * 限制最大直接内存大小100m * 直接内存溢出 */ public class DirectOom { public static void main(String[] args) { //直接分配128M的直接内存(100M) ByteBuffer bb = ByteBuffer.allocateDirect(128*1024*1204); } }
运行结果:
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 com.jvm.ch05.oom.DirectOom.main(DirectOom.java:13)
虚拟机允许的直接内存为100M.但是ByteBuffer 需要128M的空间,所以发生直接内存溢出OutOfMemoryError: Direct buffer memory。
方法区溢出java.lang.OutOfMemoryError: Metaspace
一般发生在动态语言,因为动态语言编译后会放在方法区。
在经常动态生产大量Class的应用中,CGLIb字节码增强,动态语言,大量JSP(JSP第一次运行需要编译成Java类),基于OSGi的应用(同一个类,被不同的加载器加载也会设为不同的类)。如果方法区内存不够大的话也会发生java.lang.OutOfMemoryError: Metaspace溢出。
“前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。”
大功告成!!