- 内存溢出的原因
- 栈溢出
- 栈溢出的第1种情况,死递归,抛出StackOverflowError
- 栈溢出的第2种情况,线程太多,抛出OutOfMemoryError
- 堆溢出
- 1.初始对象太大,超过机器内存,抛出OutOfMemoryError: Java heap space
- 2.在方法执行中,回收效率不足2%,抛出OutOfMemoryError: GC overhead limit exceeded
- 直接内存溢出 Direct buffer memory
- 方法区溢出java.lang.OutOfMemoryError: Metaspace
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调整,一般不用调整
),反复调用,会超出栈溢出。
如果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 exceededdemo如下:
/**
*
* 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
。
分配的本地内存大小大于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溢出。
开通了个微信公众号:
搜索: 怒放de每一天
后续可能不定时推送相关文章,期待和大家一起成长!!
大功告成!!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)