对学Java来说,JVM重要吗?

曾经,有个项目时不时总是会报错:

java.lang.OutOfMemoryError: GC overhead limit exceeded

这个问题几个同事都没搞定,就来找我。我看了看,突然想起来,以前在官方调优指南《HotSpot Virtual Machine Garbage Collection Tuning Guide》看到过相关介绍。

JVM 本身内存不足就会运行 GC,但是如果每次 GC 回收的内存不够,那么很快就会开始下一次 GC。

JVM 有个默认的保护机制,如果发现在一个统计周期内,98% 的时间都是在运行 GC,内存回收却少于 2% 的时候,就会报这个错。

怎么引起的呢?这个问题如果去排查代码,那真的是难如登天,首先,没有任何堆栈错误去帮助定位问题。其次,项目代码量大了去了,而且是年头久远。

这时,就需要通过对 JVM 总体的深入理解,去反推问题了。我当时是这样推理的:

内存溢出,GC 无法回收问题,说明了两个问题:

  1. 堆内的内存不够用了
  2. 占用内存的对象要么就是该关闭的资源没有关闭,要么被大量的暂时放在一起了

那如果我 dump 出内存文件出来,再分析下就知道是哪些对象在占用内存了。

一查发现是大量的字符串在占用内存。

综合我前面的推测,字符串不是数据库连接,肯定没有该关闭未关闭的问题。那就剩一个可能了,就是被大量的暂时放起来了,导致 GC 回收不了。

那么新问题来了,能大量放字符串的,会是什么?

首先就去猜缓存。根据这条线索,直接去源码搜 Cache 关键词,把所有关于 Cache 的代码都看了下。一下子就找到问题了。

原来,我们有个功能是解析一个非常大的文件。文件的格式如下:

需要把这个文件的每一行内容按照列去一起存到数据库里。

由于写代码的人偷懒,想一次解析完毕后一股脑全塞到数据库里。所以,他弄了个 Map,Map 的 Key 是相同的列名,Value是每一行解析过的内容。

而这样写代码的结果就是,一行对应了一个有三个条目的 HashMap。如果文件有十几万行,就有十几万的 HashMap。然后,这些 HashMap 再存到一个列表里,再把这个列表放到一个叫做 xxxCache 的 HashMap 中。

示意代码如下:

public class ParseFile4OOM {
   
    public static void main(String[] args) {
   
        List<Map<String, String>> lst = new ArrayList&
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值