返回首页 | 注册送体验金88送现金

合作共赢、快速高效、优质的网站建设提供商

更多精品源码-尽在织梦模板-www.moke8.com

[编码]Java内存溢出(OutOfMemoryError)

时间:2017-07-31 编辑:admin

在正式开始讲解关于OutOfMemoryError错误之前先来了解下,我在遇到这个异常的背景。

对数据充满敬畏之心

我需要对hive中的数据进行批量操作处理,对于没有了解过hive的同学来说,有点茫然了。于是按照常规思路开始通过JDBC连接Hive读取数据 - 处理数据 - 写入数据。

貌似没有什么不妥的,于是乎噼里啪啦代码写好了 - 调试 - 验证 - 上线批量处理数据。上线处理数据的过程出问题了,为什么半天没有处理完一条数据?

被坑了,Hive可不是MySQL能够在ms内返回结果给你,这下傻了,处理一条数据需要几分钟到十几分钟不等,简直不能忍啊。

不能忍了能怎么办,能怎么办优化解决方案呗。而是借助Hive分布式MR的能力将输入数据先处理一遍按照读取的顺序给整理好存放到中间表 - 批量操作中间表 - 数据写回。

开始接近了本篇要讲解的主题了,进行批量操作数据而导致OutOfMemoryError。

为什么会出现OutOfMemoryError

相信有一定编程经验的开发人员都会遇到这个错误,其实出现这个错误大家肯定想到的原因:是不是程序写的有问题产生了大量垃圾对象没法被JVM回收掉,亦或者是程序的正常逻辑确实需要用到比JVM提供的堆区内存大。

本人在遇到这个错误的时候也是这么怀疑过,于是首先去检查了下自己的代码,因为逻辑代码比较少仔细分析后发现程序写的没问题,不应该出现无法被JVM回收的内存垃圾。那怎么验证自己的代码没有出现内存垃圾?

通过 jmap -histo:live pid 可以分析出所有存活的对象所占用的内存大小。

?

发现在跳出批量处理数据的逻辑后,所有相关的内存都被回收了,所以确认没有内存垃圾。

那就只能是处理的数据超过了JVM堆区内存上限,按照这个猜测往下分析。

首先来观察下机器内存的变化情况jstat -gc pid 5000 100 后面两个参数一个是间隔多久统计一次,总共统计多少次。不了解可以自行搜索资料了解这个命令的输出参数。

?

确实内存会在一段时间后大量释放,然后随着运行又将整个堆区给占满了。到这里可以确定是由于批量处理数据太多而使线程所拥有的堆区撑爆了。

本来分析应该到这里为止了,但是得知道是什么将堆区给占满了吧?

什么将内存给占满了

首先通过这篇文章了解Java一个对象在内存中分配的字节数为多少。

通过jmap -histo:live pid 查看在内存满和不满的时候其中存活的对象。

?

主要暴增对象如上图框出来的地方。

TestObject定义如下:

public class TestObject {
 private String a;
 private String b;
 private String c;
 private String d;
 private Integer e;
 private Integer f;
}

从TestObject的定义和上图存活对象的对比就可以判断出java.lang.String、java.lang.Integer、[C暴增的原因了。

TestObject size = 194664000/4866600 = 40

String size = 514238640/21426610 = 24

符合Java对象内存一篇文中分析的字节大小。

JVM内存波动

?

根据JVM对内存的使用策略我们可以看到堆内存容量在各个部分进行波动,内存波动的同时GC回收的频次。


浏览:

网站建设

流程

    网站建设流程