Java内存溢出情况

简介: 在Java运行时数据区中,除了Program Counter Register(程序计数器)之外,其他几个数据区中均可能发生OutOfMemoryError,俗称OOM。

在Java运行时数据区中,除了Program Counter Register(程序计数器)之外,其他几个数据区中均可能发生OutOfMemoryError,俗称OOM。

1.Java堆溢出

堆主要是用于对象创建时内存的分配,只要我们不断创建对象,并且这些对象在GC时不会被回收掉,则会发生Java堆内存溢出。我们通过以下程序来模拟Java堆溢出的情况:

首先配置虚拟机参数,将堆大小设置为20M并且不可扩展:

-verbose:gc -Xms20M -Xmx20M -XX:+PrintGCDetails
public class Test { 
    public static class Obj {   
    }
    
    public static void main(String[] args) throws Exception {        
        List<Obj> list = new ArrayList<Obj>();
        while(true) {
                //循环创建对象,并且对象并不能被回收
            list.add(new Obj());
        }
    }
}

运行结果如下:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Arrays.java:2245)
    at java.util.Arrays.copyOf(Arrays.java:2219)
    at java.util.ArrayList.grow(ArrayList.java:242)
    at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:216)
    at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:208)
    at java.util.ArrayList.add(ArrayList.java:440)
    at Test.main(Test.java:13)

Java堆内存溢出是最常见的内存溢出情况,出现Java堆的OOM时,异常栈信息一般会有java.lang.OutOfMemoryError: Java heap space

2.虚拟机栈溢出

当线程执行一个方法时,java虚拟机会创建一个新的栈帧(stack frame),并压入到该线程的栈中,只要这个方法没有返回,这个栈帧就一直存在于栈中。如果方法嵌套调用层次太多(如上面的递归调用),则该线程栈中的栈帧会越来越多,并且方法都没有结束返回,这些栈帧也不会出栈,最终导致这个线程的栈中所有栈帧的大小总和大于-Xss设置的值,从而产生StackOverflowError异常。

本地方法栈与虚拟机栈类似,在这里会有2种溢出情况:

  1. 如果线程请求的栈深度大于虚拟机所允许的最大深度,则抛出StackOverflowError异常;
  2. 如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。

我们来模拟栈溢出情况,首先配置虚拟机参数,设置栈大小为160k:

-verbose:gc -Xss160k -XX:+PrintGCDetails
public class Test { 
    
    private int l = 1;
    
    public void callMethod() {
        System.out.println(l);
        l++;
        callMethod();
    }
    
    public static void main(String[] args) throws Exception {        
        Test t = new Test();
        try {
            t.callMethod();         
        } catch(Exception e) {
            System.out.println("stack length : " + t.l);
            throw e;
        }
    }
}

运行结果如下:

Exception in thread "main" java.lang.StackOverflowError
    at Test.callMethod(Test.java:11)
    at Test.callMethod(Test.java:12)
    at Test.callMethod(Test.java:12)
        ......
        ......

在单线程下测试以上代码时,发现只会抛出StackOverflowError异常。

3.方法区的溢出

方法区用于存放Class信息、常量等,方法区的内存溢出主要有2种情况:

  1. 现在的很多主流框架如Spring,会在运行时生成大量的增强类,增强的类越多,就需要越大的方法区来保存动态生成的Class信息,因此也越容易发生内存溢出。
  2. 运行时常量池内存溢出。
    我们可以使用String.intern()方法不断生成字符串常量来模拟内存溢出,同样先设置方法区的内存大小。
-verbose:gc -XX:PermSize=4M -XX:MaxPermSize=4M -XX:+PrintGCDetails
public class Test { 
    public static void main(String[] args) {        
        List<String> list = new ArrayList<String>();
        int i = 0;
        while(true) {
            System.out.println(i);
            list.add(String.valueOf(i++).intern());
        }
    }
}

运行结果如下:

Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
    at java.lang.String.intern(Native Method)
        ......

从异常栈信息中可以看到,在java.lang.OutOfMemoryError后面跟随的是"PermGen space",这里说明常量池是属于虚拟机中永久代的一部分。

4.小结

本文主要模拟了不同的内存区域出现内存溢出的情况,当我们自己的应用程序出现内存溢出时,就能根据异常信息定位到内存溢出的代码所在。

系列文:
1.Java内存区域
2.Java内存溢出情况
3.Java垃圾回收机制

目录
相关文章
|
14天前
|
存储 Java 编译器
Java内存区域详解
Java内存区域详解
29 0
Java内存区域详解
|
24天前
|
缓存 算法 Java
Java内存管理与调优:释放应用潜能的关键
【4月更文挑战第2天】Java内存管理关乎性能与稳定性。理解JVM内存结构,如堆和栈,是优化基础。内存泄漏是常见问题,需谨慎管理对象生命周期,并使用工具如VisualVM检测。有效字符串处理、选择合适数据结构和算法能提升效率。垃圾回收自动回收内存,但策略调整影响性能,如选择不同类型的垃圾回收器。其他优化包括调整堆大小、使用对象池和缓存。掌握这些技巧,开发者能优化应用,提升系统性能。
|
1月前
|
监控 Java 数据库连接
解析与预防:Java中的内存泄漏问题
解析与预防:Java中的内存泄漏问题
|
20天前
|
缓存 安全 Java
Java并发编程进阶:深入理解Java内存模型
【4月更文挑战第6天】Java内存模型(JMM)是多线程编程的关键,定义了线程间共享变量读写的规则,确保数据一致性和可见性。主要包括原子性、可见性和有序性三大特性。Happens-Before原则规定操作顺序,内存屏障和锁则保障这些原则的实施。理解JMM和相关机制对于编写线程安全、高性能的Java并发程序至关重要。
|
28天前
|
缓存 Java C#
【JVM故障问题排查心得】「Java技术体系方向」Java虚拟机内存优化之虚拟机参数调优原理介绍(一)
【JVM故障问题排查心得】「Java技术体系方向」Java虚拟机内存优化之虚拟机参数调优原理介绍
79 0
|
2月前
|
存储 安全 Java
一文带你读懂深入理解Java内存模型
java内存模型(Java Memory Model,JMM)是java虚拟机规范定义的,用来屏蔽掉java程序在各种不同的硬件和操作系统对内存的访问的差异,这样就可以实现java程序在各种不同的平台上都能达到内存访问的一致性。可以避免像c++等直接使用物理硬件和操作系统的内存模型在不同操作系统和硬件平台下表现不同,比如有些c/c++程序可能在windows平台运行正常,而在linux平台却运行有问题。 物理硬件和内存
21 1
|
2天前
|
Java 程序员 数据库连接
Java从入门到精通:3.3.2性能优化与调优——内存管理篇
Java从入门到精通:3.3.2性能优化与调优——内存管理篇
Java从入门到精通:3.3.2性能优化与调优——内存管理篇
|
3天前
|
存储 安全 Java
滚雪球学Java(19):JavaSE中的内存管理:你所不知道的秘密
【4月更文挑战第8天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
30 4
滚雪球学Java(19):JavaSE中的内存管理:你所不知道的秘密
|
10天前
|
存储 缓存 监控
Java内存管理:垃圾回收与内存泄漏
【4月更文挑战第16天】本文探讨了Java的内存管理机制,重点在于垃圾回收和内存泄漏。垃圾回收通过标记-清除过程回收无用对象,Java提供了多种GC类型,如Serial、Parallel、CMS和G1。内存泄漏导致内存无法释放,常见原因包括静态集合、监听器、内部类、未关闭资源和缓存。内存泄漏影响性能,可能导致应用崩溃。避免内存泄漏的策略包括代码审查、使用分析工具、合理设计和及时释放资源。理解这些原理对开发高性能Java应用至关重要。
|
18天前
|
存储 缓存 安全
【企业级理解】高效并发之Java内存模型
【企业级理解】高效并发之Java内存模型