常见的Java内存溢出情况和实例

常见的Java内存溢出情况和实例,第1张

文章目录
    • 内存溢出的原因
    • 栈溢出
      • 栈溢出的第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调整,一般不用调整),反复调用,会超出栈溢出。

栈溢出的第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溢出。


开通了个微信公众号:
搜索: 怒放de每一天
后续可能不定时推送相关文章,期待和大家一起成长!!


大功告成!!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/727061.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-26
下一篇 2022-04-26

发表评论

登录后才能评论

评论列表(0条)

保存