java堆溢出_JVM 堆(heap)溢出案例

一、说明

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

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

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

二、原因及解决办法

OutOfMemoryError 异常的常见原因:

加载的数据过大。如:加载的文件或者图片过大、一次从数据库取出过多数据

代码存在死循环或循环产生过多的对象

解决方法

增加jvm的内存大小,使用 -Xmx 和 -Xms 来设置

检查代码中是否有死循环或递归调用。

检查是否有大循环重复产生新对象实体。

检查对数据库查询中,是否有一次获得全部数据的查询。一般来说,如果一次取十万条记录到内存,就可能引起内存溢出。这个问题比较隐蔽,在上线前,数据库中数据较少,不容易出问题,上线后,数据库中数据多了,一次查询就有可能引起内存溢出。因此对于数据库查询尽量采用分页的方式查询。

检查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 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 查看的内存信息

5d7d72aedb14162b528d78637be91884.png

1f716673a5896f2c0069845df765f224.png

4d04879e9d106ce24e13016ad74f0b64.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值