TraeCode 的 100 种用法|线上服务 OOM 崩了三次,我把 core dump 分析全交给 TraeCode 了

TraeCode 的 100 种用法|线上服务 OOM 崩了三次,我把 core dump 分析全交给 TraeCode 了

上周连续三个晚上被电话叫起来,线上一个数据处理服务 OOM 崩了。第一次以为是偶发,第二次开始慌,第三次 leader 直接说"明天之前给我个说法"。

排查过程

服务是 Java 的,跑了大概两天就会 OOM。Heap dump 拿到了,大概 3GB 多,用 MAT 打开看了半天,看到一堆 byte[] 和 char[] 占了大头,但具体是哪段业务代码在疯狂创建对象,MAT 给的调用链太深了,看得我脑壳疼。

后来我换了个思路——把 MAT 的 histogram 和 dominator tree 导出成文本,丢给 TraeCode 分析。

TraeCode 怎么帮我定位的

我把三份数据一起丢进去:

  1. MAT 导出的对象分布直方图(top 50)
  2. Dominator tree 的前 30 行
  3. 相关的业务代码(几个疑似有大对象创建的 Service 类)

TraeCode 做了几件事:

第一步,它先分析了对象分布,指出 byte[] 占了堆内存的 62%,其中大部分是 1MB 以上的超大对象。结合 dominator tree,它判断问题出在一个数据导入模块——有个 ByteArrayOutputStream 在不断追加数据但没有设置上限。

第二步,它扫了我给的那几个 Service 类代码,找到了具体的问题代码:

// 问题代码
public void importData(InputStream input) {
    ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    byte[] chunk = new byte[8192];
    int read;
    while ((read = input.read(chunk)) != -1) {
        buffer.write(chunk, 0, read);
    }
    // 整个文件内容全在内存里
    processData(buffer.toByteArray());
}

它指出这个方法把整个输入流读到内存里,如果上传的文件有几百 MB,直接就把堆撑爆了。

第三步,它给了修复方案:用流式处理替代全量加载。

// 修复后
public void importData(InputStream input) {
    BufferedInputStream bis = new BufferedInputStream(input);
    CsvReader reader = new CsvReader(bis); // 逐行读取
    List<Record> batch = new ArrayList<>(1000);
    while (reader.hasNext()) {
        batch.add(reader.next());
        if (batch.size() >= 1000) {
            processBatch(batch);
            batch.clear();
        }
    }
    if (!batch.isEmpty()) {
        processBatch(batch);
    }
}

还有一个隐藏的问题

修完上面的代码后压测了一下,发现内存还是涨得比较快。TraeCode 帮我看了一下 GC 日志,发现 Young GC 频率正常但 Full GC 之后老年代还是占了 70%。

它怀疑有内存泄漏,建议我用 jmap -histo:live 对比两次 heap dump 的差异。我照做了,两次 dump 间隔 10 分钟,对比发现某个 ConcurrentHashMap 的 size 一直在涨。

最后定位到一个本地缓存没有设置过期时间,一直在往里面塞数据。加上 Caffeine 的 expireAfterWrite(30, MINUTES) 之后,内存终于稳住了。

最终效果

  • 修复前:运行约 48 小时 OOM,堆峰值 3.5GB
  • 修复后:连续运行 5 天稳定,堆峰值 800MB,Full GC 从每天 3-4 次降到 0 次

整个排查过程大概花了两天。如果纯靠自己看 MAT 和 GC 日志,估计得四五天。TraeCode 最大的帮助是把 MAT 那些晦涩的数据翻译成了具体的代码位置,省了大量人肉排查的时间。


1 个赞