文章目录
- 1、背景
- 2、快照文件分析
- 3、本地环境复现
- 4、结论
- 5、解决方式
1、背景
文章微服务升级,新增了一个传入文章id的List,判断有多少id是存在的接口,第二天高峰期内存溢出。
2、快照文件分析
打开直方图,发现线程对象占用排第一。打开支配树,按深堆排序,选占用最大的线程对象,找到处理器方法HandlerMethod,List objects –> with outgoing references查看其关联的对象
在description中方找到当前线程在执行哪个方法
再回到支配树,发现有个字符串对象,深堆非常大,里面是一句SQL,而字符串底层是用字符数组实现的,其下方的char有157w大小,且char的浅堆也很大,点击发现里面是frch_item,而它的产生是因为SQL在拼接过程中用了foreach去遍历了一个大集合:
3、本地环境复现
找到快照文件中的相关代码:
@RestController
@RequestMapping("/sqljoint")
public class DemoSqlJointController {
/**
* 服务对象
*/
@Resource
private TbArticleService art服务器托管icleService;
/**
* 判断批量id存在多少个
* size:传入生成的id数量
*/
@GetMapping
public ResponseEntity countIfAbsent(int size) {
//随机生成批量id,模拟传入一个id的List
ListInteger> ids = new Random().ints(0, 1000000).
limit(size).boxed().collect(Collectors.toList());
return ResponseEntity.ok(this.articleService.countIfAbsent(ids));
}
}
Mapper层用foreach做了一个遍历
select id="countIfAbsent" resultType="java.lang.Long">
select
IFNULL(sum(1),0)
from article where
if test="ids != null and ids.size() > 0">
id in
foreach collection="ids" item="item" open="(" close=")" separator=",">
#{item}
foreach>
if>
select>
在本地启动Jmeter,调整size的值
Visual发现siz服务器托管e大时,JVM堆内存溢出
4、结论
Mybatis在使用foreach进行sql拼接时,会在内存中创建对象,如果foreach处理的数组或者集合元素个数过多,会占用大量的内存空间。
5、解决方式
- 限制id个数的最大值
- 将id缓存到redis,先用内存查
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
前言 这篇博客博主将详细地介绍有关网络知识的一些相关概念,坐好板凳发车啦~ 一相关知识 1.1IP地址 IP地址主要用于标识网络主机、其他网络设备(如路由器)的网络地址。简单来说,IP地址用于定位主机的网络地址。 IP地址是一个32位的二进制数,通常被分割为4…