资讯专栏INFORMATION COLUMN

Java内存溢出(OutOfMemoryError)

calx / 486人阅读

摘要:那就只能是处理的数据超过了堆区内存上限,按照这个猜测往下分析。主要暴增对象如上图框出来的地方。符合对象内存一篇文中分析的字节大小。优化自己的程序,使其在运行过程中占用内存尽可能的少。针对异常的具体优化措施。

前言

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

对数据充满敬畏之心

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

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

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

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

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

为什么会出现OutOfMemoryError

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

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

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


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

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

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


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

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

什么将内存给占满了

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

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


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

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内存管理很多前辈都已经讲的非常清楚了,根据理论我们来实际窥探下JVM是如何针对内存进行管理的,同时如何进行内存回收。


根据JVM对内存的使用策略我们可以看到程序不断使用内存的过程中堆内存容量在各个部分的波动情况,在新生代/老生代内存达到一定百分比的同时GC回收的回收情况。

触发条件:
老生代:1043574/1329152 = 0.78 (-XX:CMSInitiatingOccupancyFraction 参数控制容量达到多少进行FGC)
新生代:在Eden区满后触发

总结

针对OutOfMemoryError优化手段无非两种:

加大堆区内存。

优化自己的程序,使其在运行过程中占用内存尽可能的少。

针对OutOfMemoryError异常的具体优化措施。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/67527.html

相关文章

  • Java内存区域及内存溢出

    摘要:直接通过可以造成本机内存溢出。小节内存区域描述异常程序计数器略略略虚拟机栈存放编译器可知的各种基本类型,对象引用和类型每个线程的栈大小堆存放对象实例最大值最小值运行时常亮池存放编译期生成的字面量和符号引用,运行期也能放入常量池。 堆溢出 Java堆用于存储对象实例,只要不断地创建对象,并且保证GC Roots到对象之间有可达路径避免垃圾回收,当到达最大堆的容量限制后就会产生Java.l...

    cheukyin 评论0 收藏0
  • Java 常见内存溢出异常与代码实现

    摘要:堆堆是用来存储对象实例的因此如果我们不断地创建对象并且保证和创建的对象之间有可达路径以免对象被垃圾回收那么当创建的对象过多时会导致内存不足进而引发异常上面是一个引发异常的代码我们可以看到它就是通过不断地创建对象并将对象保存在中防止其被 Java 堆 OutOfMemoryError Java 堆是用来存储对象实例的, 因此如果我们不断地创建对象, 并且保证 GC Root 和创建的对象...

    whatsns 评论0 收藏0
  • 【修炼内功】[JVM] 浅谈虚拟机内存模型

    摘要:也正是因此,一旦出现内存泄漏或溢出问题,如果不了解的内存管理原理,那么将会对问题的排查带来极大的困难。 本文已收录【修炼内功】跃迁之路 showImg(https://segmentfault.com/img/bVbsP9I?w=1024&h=580); 不论做技术还是做业务,对于Java开发人员来讲,理解JVM各种原理的重要性不必再多言 对于C/C++而言,可以轻易地操作任意地址的...

    sanyang 评论0 收藏0
  • 关于JVM内存溢出的原因分析及解决方案探讨

    摘要:内存溢出分配的内存空间超过系统内存。内存泄漏的原因分析由大块组成堆,栈,本地方法栈,程序计数器,方法区。内存溢出的原因分析内存溢出是由于没被引用的对象垃圾过多造成没有及时回收,造成的内存溢出。小结栈内存溢出程序所要求的栈深度过大导致。 showImg(https://segmentfault.com/img/bVbweuq?w=563&h=300); 前言:JVM中除了程序计数器,其他...

    xuexiangjys 评论0 收藏0
  • 十种JVM内存溢出的情况,你碰到过几种?

    摘要:内存溢出的情况就是从类加载器加载的时候开始出现的,内存溢出分为两大类和。以下举出个内存溢出的情况,并通过实例代码的方式讲解了是如何出现内存溢出的。内存溢出问题描述元空间的溢出,系统会抛出。这样就会造成栈的内存溢出。 导言: 对于java程序员来说,在虚拟机自动内存管理机制的帮助下,不需要自己实现释放内存,不容易出现内存泄漏和内存溢出的问题,由虚拟机管理内存这一切看起来非常美好,但是一旦...

    ShevaKuilin 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<