实战项目中Java heap space错误的解决[通俗易懂]

实战项目中Java heap space错误的解决[通俗易懂] java高级面试 2018-09-0720:19:23部标GPS通讯系统在上线之后,经过不断调试,终于稳定运行一段时间,后来又遇到了Javaheapspace错误异常!日志如下: 说明系统中有未释放的对象。如何找出这些未释放对象以及监控JVM堆内存,优化代码释放内存对象呢?还有JVM的垃圾回收机制是如何运作的呢?首先在系统启动运行的时候打开记录GC详细信息,运行脚本…

大家好,又见面了,我是你们的朋友全栈君。

 

java高级面试 2018-09-07 20:19:23

部标GPS通讯系统在上线之后,经过不断调试,终于稳定运行一段时间,后来又遇到了Java heap space错误异常!日志如下:

实战项目中Java heap space错误的解决

 

说明系统中有未释放的对象。如何找出这些未释放对象以及监控JVM堆内存,优化代码释放内存对象呢?还有JVM的垃圾回收机制是如何运作的呢?

首先在系统启动运行的时候打开记录GC详细信息,运行脚本如下:

实战项目中Java heap space错误的解决

 

看看GC详细日志,当GC到13400多次的时候新生代和老生代的堆内存几乎用满了,频繁触发Full GC (Ergonomics) ,直到没有内存空间给新生对象了。所以JVM抛出了内存溢出错误!进而导致程序崩溃。

实战项目中Java heap space错误的解决

 

首先简单了解下JVM垃圾回收机制:

实战项目中Java heap space错误的解决

 

从上图可以看出 GC 的主要收集区域,包括 PSYoungGen(年轻代)、ParOldGen(老年代)、Metaspace(元数据区)。

新生代:新创建的对象都是用新生代分配内存,Eden空间不足时,触发Minor GC,这时会把存活的对象转移进幸存者Survivor区。

老年代:老年代用于存放经过多次Minor GC之后依然存活的对象。

新生代的GC(Minor GC):新生代通常存活时间较短基于Copying算法进行回收,所谓Copying算法就是扫描出存活的对象,并复制到一块新的完全未使用的空间中,对应于新生代,就是在Eden和FromSpace或ToSpace之间copy。

新生代采用空闲指针的方式来控制GC触发,指针保持最后一个分配的对象在新生代区间的位置,当有新的对象要分配内存时,用于检查空间是否足够,不够就触发GC。当连续分配对象时,对象会逐渐从Eden到Survivor,最后到老年代。

老年代的GC(Major GC/Full GC):老年代与新生代不同,老年代对象存活的时间比较长、比较稳定,因此采用标记(Mark)算法来进行回收,所谓标记就是扫描出存活的对象,然后再进行回收未被标记的对象,

回收后对用空出的空间要么进行合并、要么标记出来便于下次进行分配,总之目的就是要减少内存碎片带来的效率损耗。

附上堆结构图:

实战项目中Java heap space错误的解决

 

至此,在已经尝试了将Java虚拟机中Xms(初始堆大小-2G)和Xmx(最大堆大小-4G)参数调大之后也无果,只能从代码入手, 对象一直堆积于老年代未被释放,应该是代码中对象未被释放。

为了找出代码中未被释放的对象,这里运用到了内存监控工具jconsole和内存堆对象统计工具jmap

jconsole.exe位于bin目录下,用法也挺简单的,用于调优后的监控还不错,这里留个图不做介绍了

实战项目中Java heap space错误的解决

 

这里运用jmap(jdk自带的jvm内存分析的工具),将程序堆对象统计出来的结果如下:

实战项目中Java heap space错误的解决

 

发现到代码问题:应该是解析协议的时候CanDataItem对象不断被new出来,使用完了以后并未被GC回收留在老生代,

实战项目中Java heap space错误的解决

 

找到CanDataItem使用完成的地方做了如下修改:

实战项目中Java heap space错误的解决

 

修改代码再将T808Message等类用完了的地方做了释放,之后终于解决了问题!修改代码以后再次使用jmap统计如下,正常了!

实战项目中Java heap space错误的解决

 

附 – jmap输出中class name非自定义类的说明:

BaseType CharacterTypeInterpretationBbytesigned byteCcharUnicode characterDdoubledouble-precision floating-point valueFfloatsingle-precision floating-point valueIintintegerJlonglong integerL;referencean instance of classSshortsigned shortZbooleantrue or false[referenceone array dimension,[I表示int[]

总结导致java.lang.OutOfMemoryError异常的常见原因有以下几种:

  • 内存中加载的数据量过于庞大,如一次从数据库取出过多数据;
  • 集合类中有对对象的引用,使用完后未清空,使得JVM不能回收;
  • 代码中存在死循环或循环产生过多重复的对象实体—–(本例中);
  • 使用的第三方软件中的BUG;
  • 启动参数内存值设定的过小;

至此问题总算解决了,通常情况下,Java开发人员并不需要去关心JVM是如何运行的。即使不理解JVM的工作原理,也不会给开发人员带来过多困惑。Java程序员更容易忽视基础技术。

“蚓无爪牙之利,筋骨之强,上食埃土,下饮黄泉,用心一也。蟹六跪而二螯,非蛇蟮之穴无可寄托者,用心躁也”。对于技术人员来说,如果长期忽略自身技术的根基而去一昧地追求高层框架技术,这无疑是舍本求末的做法。

JVM的出现,为程序员屏蔽了操作系统与硬件的细节,使得程序员从诸如内存管理这样的繁琐任务中解放出来。但这不并等同于允许Java程序员放弃对基础的重视。

事实上,任何平台的程序员都应当了解平台的基本特性、实现机制以及接口,这是提高自身修养的必经之路。对于Java程序员来说,我们还是需要多多了解JVM。

了解JVM的基本实现机制,不仅对于解决实际应用中诸如GC等虚拟机问题时有直接帮助,还有利于我们更好地理解语言本身。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/157007.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • pycharmpip安装_更改pip源地址

    pycharmpip安装_更改pip源地址Pycharm更换下载源更换原因在使用Pycharm的时候不免要下载许多的第三方库,特别是移植过来的项目更是一个文件的依赖包需要下载而Pycharm默认的官方源下载比较慢,我们可以通过配置来更换国内下载源靠谱的pip镜像源源清华源:https://pypi.tuna.tsinghua.edu.cn/simple豆瓣源:http://pypi.douban.com/simple/阿里源:http://mirrors.aliyun.com/pypi/simple/

    2022年8月25日
    12
  • java case when用法_sql case when 嵌套

    java case when用法_sql case when 嵌套前几天在客户环境遇到一个Spark“CASEWHEN”语句的性能优化问题。客户那边通过一个“时间范围筛选”控件来动态修改图表的数据。其很多指标的计算逻辑类似于:CASEWHEN`bizdate`BETWEEN’2020-09-06’AND’2020-09-13’THEN`sales_amount`ELSE0ENDCASEWHEN语句有些类似于编程语言中的Switch语句,当这里的…

    2025年9月18日
    4
  • intellij idea激活码_通用破解码

    intellij idea激活码_通用破解码,https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月16日
    63
  • 手机如何安装GreasyFork油猴js脚本?

    手机如何安装GreasyFork油猴js脚本?文章目录前言一、Iceraven浏览器(火狐)(安卓)二、Via浏览器(安卓)三、alook浏览器(苹果)(安卓)四、kiwi浏览器(安卓)总结前言Icaraven浏览器与kiwi浏览器的界面和功能基本相同Iceraven支持火狐插件,kiwi浏览器支持谷歌插件Via浏览器体积小。alook浏览器功能丰富。

    2022年7月15日
    78
  • laravel 是怎么做到运行 composer dump-autoload 不清空 classmap 映射关系的呢?

    laravel 是怎么做到运行 composer dump-autoload 不清空 classmap 映射关系的呢?

    2021年10月22日
    56
  • MongoVUE_mongodb怎么用

    MongoVUE_mongodb怎么用一、    连接mongodb服务端:1、         双击mongoVUE,进入如下图所示界面:2、         点击上图中的“+”,出现如下图,输入要连接的mongodb服务器的ip、端口、用户名、密码以及要连接的数据库等:3、         信息填写完成后点击“test”,如果成功,则会弹出如下界面,之后点击“save”;如果不是如下界面,代表输

    2022年8月21日
    5

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号