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

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

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溢出。


相关文章
|
3天前
|
监控 Java
Java中的内存泄漏分析与排查技巧
Java中的内存泄漏分析与排查技巧
|
4天前
|
存储 监控 算法
Java堆栈内存管理与优化技巧的实践指南
Java堆栈内存管理与优化技巧的实践指南
|
4天前
|
存储 缓存 安全
阿里云服务器实例规格选择参考:经济型、通用算力型、计算型、通用型、内存型区别
当我们在通过阿里云的各种活动选择云服务器实例规格的时候会发现,相同配置的云服务器往往有多个不同的实例可选,而且价格差别也比较大,这会是因为不同实例规格的由于采用的处理器不同,底层架构也有所不同(例如X86 计算架构与Arm 计算架构),因此不同实例的云服务器其性能与适用场景是有所不同。目前阿里云的活动中,主要的实例规格可分为经济型、通用算力型、计算型、通用型、内存型,对于很多初次接触阿里云服务器的用户来说,了解他们之间的差别就是比较重要的了,下面小编来为大家简单介绍下它们之间的区别。
阿里云服务器实例规格选择参考:经济型、通用算力型、计算型、通用型、内存型区别
|
3天前
|
安全 Java 编译器
深入解析Java内存模型
本文旨在探讨Java内存模型的设计理念、核心原理及其在并发编程中的应用。通过分析内存模型的结构组成,阐述其在确保多线程环境下数据一致性和可见性方面的关键作用。进一步讨论同步机制、happens-before原则以及内存屏障等概念,并结合实例代码演示如何正确利用Java内存模型进行高效并发编程。
|
3天前
|
存储 缓存 NoSQL
Java中的内存数据库与缓存技术
Java中的内存数据库与缓存技术
|
4天前
|
Java
正则表达式在Java中的应用与实例
正则表达式在Java中的应用与实例
|
4天前
|
监控 Java 数据库连接
如何避免Java中的内存泄漏?
如何避免Java中的内存泄漏?
|
5天前
|
安全 Java
|
5天前
|
监控 算法 Java
如何优化Java应用程序的内存管理
如何优化Java应用程序的内存管理
|
1天前
|
存储 算法 Java
深入理解Java中的堆与栈的内存管理
深入理解Java中的堆与栈的内存管理