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

部标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 CharacterTypeInterpretation B byte signed byte C char Unicode character D double double-precision floating-point value F float single-precision floating-point value I int integer J long long integer L; reference an instance of class S short signed short Z boolean true or false [ reference one array dimension,[I表示int[]

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

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

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

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

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

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

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

转载请注明出处!谢谢!https://www.cnblogs.com/lys_013/p/9605352.html

Original: https://www.cnblogs.com/lys_013/p/9605352.html
Author: 13
Title: 实战项目中Java heap space错误的解决

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/594317/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 一文带你搞懂 JWT 常见概念 & 优缺点

    在 JWT 基本概念详解这篇文章中,我介绍了: 什么是 JWT? JWT 由哪些部分组成? 如何基于 JWT 进行身份验证? JWT 如何防止 Token 被篡改? 如何加强 JW…

    Java 2023年6月9日
    089
  • 【spring源码学习】spring的事务管理源码学习

    一、抽象概念 1、事务管理器 接口:org.springframework.transaction.PlatformTransactionManager 实现类:org.sprin…

    Java 2023年5月29日
    071
  • Java 注解及其底层原理

    什么是注解? 注解的分类 Java自带的标准注解 元注解 @Retention @Documented @Target @Inherited @Repeatable 自定义注解 自…

    Java 2023年6月15日
    069
  • Redis 安装与使用

    Redis 介绍 Redis 是由 Salvatore Sanfilippo 写的 key-value 存储系统,是一个跨平台的非关系型数据库(NoSQL)。 Redis 是用C语…

    Java 2023年6月16日
    079
  • (转)微信扫码登录网页实现原理

    扫码登录操作过程 浏览器输入:https://wx.qq.com/?lang=zh_CN 手机登录微信,利用”扫一扫”功能扫描网页上的二维码 手机扫描成功后…

    Java 2023年6月15日
    090
  • Java: State Pattern

    java;gutter:true; /<em><em> * 版权所有 2022 涂聚文有限公司 * 许可信息查看: * 描述: * 状态模式 State P…

    Java 2023年6月16日
    069
  • IDEA分析JAVA内存溢出和内存泄漏

    参考资料: 1、JProfiler分析dump文件 https://blog.csdn.net/axin1240101543/article/details/105142141 2…

    Java 2023年5月29日
    0108
  • MYSQL 免安装

    本文使用mysql 8.0.22进行演示 一、MYSQL 下载 官网下载:地址:https://dev.mysql.com/downloads/mysql/ 阿里云盘:链接:htt…

    Java 2023年6月5日
    0144
  • 自己动手实现一个阻塞队列

    阻塞队列介绍 顾名思义,阻塞队列是一个具备先进先出特性的队列结构,从队列末尾插入数据,从队列头部取出数据。而阻塞队列与普通队列的最大不同在于阻塞队列提供了阻塞式的同步插入、取出数据…

    Java 2023年6月8日
    072
  • 题目:完成网站的咨询聊天(UDP)

    题目:完成网站的咨询聊天(UDP) 学生端: package com.gao.Project.Pro6; import java.io.IOException; import ja…

    Java 2023年6月5日
    083
  • java 双因素认证(2FA)TOTP demo

    TOTP 的全称是”基于时间的一次性密码”(Time-based One-time Password)。它是公认的可靠解决方案,已经写入国际标准 RFC62…

    Java 2023年6月16日
    089
  • SAP S4HANA 2021 Fully-Activated Appliance 虚拟机版分享

    该版本内置了四个Client: 1、000:SAP初始Client,原则上不能动; 2、100:只激活了US/DE两套BP,带大量Demo数据,可做数据参考; 3、200:复制Cl…

    Java 2023年5月30日
    089
  • jvm:内存结构与对象内存解析

    java的跨平台性主要是因为其字节码文件可以在任何具有java虚拟机的计算机或者电子设备上运行,jvm中的字节码解析器负责将字节码文件解释成机器码运行,字节码文件.class是ja…

    Java 2023年6月7日
    084
  • MySQL十七:Change Buffer

    转载~ 在之前的文章介绍的InnoDB的存储结构的组成中,我们知道Change Buffer也是用InnoDB内存结构的组成部分。 Change Buffer主要是为了在写入是减少…

    Java 2023年6月8日
    0114
  • Java—Stream进阶

    由于本文需要有一定的Stream基础,不懂什么是Stream的同学请移步:Java—Stream入门 操作分类 graph LR 操作分类 — 中间操作 终…

    Java 2023年6月7日
    085
  • Spring Bean 循环依赖

    创建 A 实例时需要 B,创建 B实例时需要 A。 测试环境:https://gitee.com/jhxxb/MySpringBoot/tree/master/Spring-Bas…

    Java 2023年5月30日
    078
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球