JVM 堆(heap)溢出案例

栏目: Java · 发布时间: 5年前

内容简介:当虚拟机申请不到内存空间的时候,会报堆内存溢出:常见的原因:我测试到时候,运行在 16G 内存的机器上。JVM 堆内存 默认为物理内存的1/4,即

一、说明

当虚拟机申请不到内存空间的时候,会报堆内存溢出: OutOfMemoryError:java heap space

常见的原因: http://outofmemory.cn/c/java-...

我测试到时候,运行在 16G 内存的机器上。JVM 堆内存 默认为物理内存的1/4,即 16 * 1/4 = 4G

JDK 8的 JVM 在 JDK 7 的基础上从堆内存中移除了 永久代(Perm Generation) ,替换为了堆内存之外的 元空间(Metaspace) ,元空间是堆外直接内存,不受堆内存的限制,只受物理内存的限制,可以提供更大的空间。

二、原因及解决办法

OutOfMemoryError异常的常见原因:

  1. 加载的数据过大。如:加载的文件或者图片过大、一次从数据库取出过多数据
  2. 代码存在死循环或循环产生过多的对象

解决方法

  1. 增加jvm的内存大小,使用 -Xmx 和 -Xms 来设置
  2. 检查代码中是否有死循环或递归调用。
  3. 检查是否有大循环重复产生新对象实体。
  4. 检查对数据库查询中,是否有一次获得全部数据的查询。一般来说,如果一次取十万条记录到内存,就可能引起内存溢出。这个问题比较隐蔽,在上线前,数据库中数据较少,不容易出问题,上线后,数据库中数据多了,一次查询就有可能引起内存溢出。因此对于数据库查询尽量采用分页的方式查询。
  5. 检查List、Map等集合对象是否有使用完后,未清除的问题。List、MAP等集合对象会始终存有对对象的引用,使得这些对象不能被GC回收。

三、代码示例

/**java堆溢出实例
 * 原理:java的堆是用来存放对象实例的,所以我们只要做到以下三点就可以使堆溢出:
 * 1、限制堆的大小,不可扩展
 * 2、不断新建对象
 * 3、保持对象存活不被回收
 * 对应的,我们需要:
 * 1、改变JVM的启动参数,将堆的最小值和最大值设成一样,这样就可以避免堆自动扩展(其实不一样也可以)
 * 2、不断产生对象
 * 3、使用一个List来保存对象,保持对象存活
 *
 * JVM配置参数: -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
 *
 */
public class HeapOom {
    public static void main(String[] args) {
        // 此list实例会存放在堆内存中
        List<byte[]> list = new ArrayList<>();
        int i = 0;
        boolean flag = true;
        while (flag) {
            try {
                i++;
                // 每次增加一个1M大小的数组对象
                list.add(new byte[1024 * 1024]);
            } catch (Throwable e) {  // catch 捕获的是 Throwable,而不是 Exception。因为 OutOfMemoryError 不属于 Exception 的子类。
                e.printStackTrace();
                flag = false;
                // 记录次数
                System.out.println("count=" + i);
            }
        }

        // 不让进程结束,便于使用分析 工具 来查看内存情况
        try {
            Thread.sleep(24 * 60 * 60 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

使用的 java 1.8.0_171 版本:

$ java -version
java version "1.8.0_171"
Java(TM) SE Runtime Environment (build 1.8.0_171-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.171-b11, mixed mode)

报错信息:

count=3316
java.lang.OutOfMemoryError: Java heap space
    at com.song.HeapOom.main(HeapOom.java:21)

运行结果表明,运行到 3316 次时,出现了 堆内存溢出 。由于每次增加1M内存。粗略估计:程序大约使用3G内存时,出现了内存溢出情况。

通过jmap或VisualVM 者工具可以查看内存情况:最后可以看出,老年代内存使用情况,大约使用了2709MB,使用率近100%。从而导致了 OutOfMemoryError

TIPS:下面查看内存时,由于使用工具查看内存的时间不是同一时间,所以内存使用量有细微差别

1. 使用jmap查看的内存信息

$ jmap -heap 3428
Attaching to process ID 3428, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.66-b18

using thread-local object allocation.
Parallel GC with 4 thread(s)

Heap Configuration:
   MinHeapFreeRatio         = 0
   MaxHeapFreeRatio         = 100
   MaxHeapSize              = 4261412864 (4064.0MB)
   NewSize                  = 88604672 (84.5MB)
   MaxNewSize               = 1420296192 (1354.5MB)
   OldSize                  = 177733632 (169.5MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize            = 21807104 (20.796875MB)
   CompressedClassSpaceSize = 1073741824 (1024.0MB)
   MaxMetaspaceSize         = 17592186044415 MB
   G1HeapRegionSize         = 0 (0.0MB)

Heap Usage:
PS Young Generation
Eden Space:
   capacity = 637009920 (607.5MB)
   used     = 637009920 (607.5MB)
   free     = 0 (0.0MB)
   100.0% used
From Space:
   capacity = 11010048 (10.5MB)
   used     = 0 (0.0MB)
   free     = 11010048 (10.5MB)
   0.0% used
To Space:
   capacity = 11010048 (10.5MB)
   used     = 0 (0.0MB)
   free     = 11010048 (10.5MB)
   0.0% used
PS Old Generation  // 老年代内存使用情况,大约使用了2709MB,使用率近100%(导致OutOfMemoryError)
   capacity = 2841116672 (2709.5MB)
   used     = 2840991320 (2709.38045501709MB)
   free     = 125352 (0.11954498291015625MB)
   99.99558793198338% used

4955 interned Strings occupying 422328 bytes.

2. 使用 VisualVM 查看的内存信息

JVM 堆(heap)溢出案例

JVM 堆(heap)溢出案例

JVM 堆(heap)溢出案例


以上所述就是小编给大家介绍的《JVM 堆(heap)溢出案例》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

创新者

创新者

[美] 沃尔特 · 艾萨克森 / 关嘉伟、牛小婧 / 中信出版社 / 2016-6 / 88.00

讲述了计算机和互联网从无到有的发展历程,并为我们生动地刻画出数字时代的创新者群像。 在近200年的数字化进程中群星闪耀,艾萨克森从一个计算机程序的创造者、诗人拜伦之女埃达说起,细数了这一群站在科学与人文交叉路口的创新者,他们包括通用型电子计算机的创造者奠奇利、科学家冯·诺依曼、仙童半导体公司的“八叛逆”、天才图灵、英特尔的格鲁夫、微软的比尔·盖茨、苹果公司的乔布斯、谷歌的拉里·佩奇等。《创新......一起来看看 《创新者》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码