前不久其实写了一篇,但是由于当时没有踩到重点,所以经过这段时间的研究,终于把这个内存溢出问题彻查清楚了
背景:
我们的一个报表工具系统,核心功能当然是查看和下载,其中下载文件功能需要将报表数据都写入文件中。一直以来,系统总是会因为JVM内存溢出而宕机。
现象:
从 weblogic 日志里看,宕机前抛出了大量java.lang.OutOfMemoryError: getNewTla错误信息,而且堆栈信息中能出现各种情况,而且有的很抽象,难以看出具体由某一个功能某一个方法导致的。后来想想,内存撑满后,确实可能导致其他功能崩坏。
由于之前对JVM及检测调试手段都不熟悉,因此通过一定时间的看书学习,期间也一直做些尝试
第一次尝试:
阅读了下载功能的代码后发现,逻辑中先进行了一次全量 sql 查询返回一个 List,然后把List遍历写入文件。这个明显不对,应该利用ResultSet批次查询的特性边查询就边写入文件。不然下载过程List 持有的大量数据对象会占用很多内存。
但是改造后,效果只有轻微的提升,通过在JVM启动参数添加 -XX:+PrintGC,查看下载过程的垃圾回收情况。内存开销依然水涨船高,每次 gc 的效率都很低,很快就吃了几百M。
第二次尝试:
关注点放在了写入的文件上,文件是 xls 格式的 excel 文件,经过一定了解,我得出这么一个结论:excel 文件不是文本文件,无法直接将数据写入文件尾部,无论是 jxl 还是 poi 这种 excel工具库,一定是将全量数据以某种数据结构存于内存中,最后一次性写入。因此这部分理论上是无法优化的。
其实到这里,有点懵了
第三次尝试:
这时候通过阅读代码已经很难猜测到还有什么地方可以优化了。于是想着将下载过程中的内存快照给 dump 出来,然后通过工具看能否分析出什么。
我的做法是:先通过 IDE 在逻辑结束前设置断点,然后在命令行通过 jmap 命令,生成当前内存快照的 dump(hprof) 文件。最后通过分析工具 MAT 打开 dump 文件。
工具显示,占用内存最大的两部分,一部分和excel 工具 jxl 的某个类有关,占了70,还有一个和 sql 查询某个类有关,占了30%。
a. SqlRowSet
这个对象持有了30%的开销,于是在代码中搜到了这行 SqlRowSet rs = this.getJdbcTemplate().queryForRowSet(sql);
了解后知道,这个类是对 ResultSet 的一种扩展,用法和 ResultSet 极为相似,区别在于,SqlRowSet会持有全量的查询数据,那么问题就在这里了,这里居然也有一份全量数据的引用。这就很尴尬了,由于代码里变量名都是用的 rs,而且用法一样,导致之前一直以为用的是 ResultSet..... 修复完,再进行dump分析,这部分的开销确实消灭了
b. WritableCellFormat
这个类持有了大部分的内存开销,依然再代码中找到了使用的地方。原来这个类是作为 excel 单元格对象附加的一个 Format对象。而代码中对每一个单元格,都去 new 了一个 format 对象。通过 MAT 工具能查看每个对象实例的大小,一看200B,数量一多内存直接上去。这里应该改成:只需要每一列 new 一个 format 对象,同一列的单元格共用一个呗
这两个问题改完以后,确实问题都解决了。回过头来看,如果一开始就比较熟练的话,完全可以将启动参数 Xmx调小,同时加上 -XX:+HeapDumpOnOutOfMemoryError参数使得再 OOM 后自动生成 dump 文件,再用分析工具查看对象占用情况,快速解决问题。不过现在也是一个学习的过程,挺好。
分享到:
相关推荐
一次jvm 老年代oom 的dump文件样例
JVM状态监控与OOM案例分析…… 简单认识,了解
通过合理的配置JVM参数,可以显著提高应用程序的性能,解决诸如OOM等问题。本文档通过具体的案例分析,介绍了JVM的基本概念、工作原理以及调优技巧,希望能够帮助开发者更好地理解和掌握JVM调优的相关知识。
本文将详细探讨一个线上出现的OOM问题,以及如何通过日志分析、使用Eclipse的Memory Analyzer Tool(MAT)以及最佳实践来定位和解决问题。 首先,我们看到的现象是Tomcat服务器在运行过程中出现了OOM错误,这通常...
本篇文章主要探讨Spark面对OOM问题的解决方法及优化策略。 首先,我们需要了解Spark的内存模型。Spark的Executor内存分为三个部分:Execution内存、Storage内存和其他内存。Execution内存主要用于执行任务,如join...
jvm oom
为了解决 OOM 问题,我们可以通过设置 JVM 参数 -XX:MaxMetaspaceSize=512m,将 metaspace 的大小设置为 512M。这可以缓解 OOM 问题,并使 metaspace 的增长变缓。同时,我们也可以增大 sun.reflect....
OOM 9种常见原因及解决方案 以下是OOM 9种常见原因及解决方案的知识点: ...OOM 错误的解决方案主要包括调整 JVM 的堆内存空间、检查大对象的合理性、添加机器资源、做限流降级、找到持有的对象、修改代码设计等。
MemoryAnalyzer(MAT)是IBM开发的一款强大的JVM堆内存分析工具,它能够帮助开发者深入理解内存消耗,识别内存泄漏和不必要的对象留存,从而有效地解决OOM问题。 MAT主要基于.hprof文件进行分析,这种文件格式是...
1. **生成堆转储文件**:当JVM出现OOM或内存问题时,可以通过`-XX:+HeapDumpOnOutOfMemoryError` JVM参数让JVM自动生成堆转储文件,或者手动通过`jmap`命令生成。 2. **加载堆转储**:在HA或MAT中打开这个文件,...
JVM状态监控与OOM案例分析.pptx
"用于复现 OOM bug,模拟JVM调优经历-JVMTest.zip"文件提供了一个实战平台,让我们可以模拟JVM内存状况,学习如何识别和解决内存溢出问题。 首先,JVM的内存区域主要分为堆(Heap)、方法区(Method Area)、虚拟机...
2、基于代码排查OOM问题,拒绝空讲; 3、总结JVM通用的调优思路; 4、基础知识讲解透彻、详尽; 5、JVM零基础也能听懂。 第一节:学习JVM的意义和目标 1.1 意义: 1.2 目标: 第二节:JVM内存模型 1.1 概念 1.2 ...
java jvm 中关于内存溢出分享,举例说明各种情况下可能会出现的oom事故
JVM通过解析字节码(Bytecode)来运行Java应用程序,实现了“一次编写,到处运行”的理念。本篇文章将深入探讨JVM的各个方面,包括其工作原理、内存模型、垃圾收集以及性能优化。 一、JVM工作原理 Java源代码经过...
有的朋友是一直开发那种几十个人使用的内部系统,所以没机会接触和经历。有的朋友是突然遇到线上IVM生产事故,毫无头绪。...全程专注于JVM生产实践,主要解决JVM生产环境的参数优化,JVM GO问题和IVM OOM问题的处理
JVM的基础和调优【JMM 内存结构 GC OOM 性能调优 ThreadLocal】 内存泄露:是指程序在申请内存后,无法释放已申请的内存空间就造成了内存泄露, 一次的内存泄露似乎不会有大的影响,但是内存泄露堆积的后果就是内存...
本篇将通过一个简单的OOM例子来探讨这个问题的发生原因、如何复现以及如何进行问题排查。 一、OOM现象与原因 当Java应用出现OOM时,JVM会抛出`java.lang.OutOfMemoryError`异常。这通常由以下几种情况引起: 1. *...
### JVM内存问题最佳实践 #### 一、选择合适的Java虚拟机 在选择Java虚拟机(JVM)时,有几个关键因素需要考虑。首先,确保选择一个稳定的版本是非常重要的。避免使用刚刚发布或刚添加了大量新功能的版本,因为这些...