堆内存Old Generation有百万个Java Bean实例对象造成OOM(jpa使用不当造成OOM)

场景:

线上间断发生CPU飙高的问题,查看heap used,会发现在cpu飙高的时间内,机器hang住,无法响应请求

上图为pinpoint监控所示,在这2分半钟时间内发生了GC,其机器hang住

用jmap看了一下

当jvm内存为2G时

放到memoryAnalyzer(MAT)里面看一下

在unreachable jobject中

查看Object中的值,发现一个规律,那就是这些用户的cert_no全部为null

原因

查看错误日志

报错result returns more than one elements

at org.hibernate.jpa.internal.QueryImpl.getSingleResult(QueryImpl.java:539)

核心的代码就是这样一句:

// 根据certNo获取用户

User user = repository.getByCertNo(certNo);

ORM使用的是spring data jpa

这句代码有一个严重的问题,就是如果certNo = null,那就jpa会把表中所有cert_no is null的结果查询出来,我们这里有100多万的User cert_no is null(这里有一个问题,jpa可能是想把100多万都取出来,但java进程这边并不能接收这么多,可能每一次放到内存中的User对象并没有这么多)

在程序中debug的时候,会发现代码运行在这里的时候明显卡顿了很久,在这个期间就是jpa把这些对象放到内存中,然后由于一个对象无法接收这100多万的用户,导致报错:result returns more than one elements

但这里要非常注意的是:

这100多万的对象,放到了内存中,并且是unreachable的了,发生了memory leak内存泄漏

解决方案

1. 可以看到这是jpa使用不当造成的,操作大表的时候,要特别小心,对于NPE要时刻注意

2. 如果使用mybatis,不会如此

发布了442 篇原创文章 · 获赞 222 · 访问量 115万+

猜你喜欢

转载自blog.csdn.net/u013905744/article/details/102897847