记一次线上报表导出 OOM_Java head space

   日期:2020-07-15     浏览:115    评论:0    
核心提示:背景:线上报表导出 跑了没1分钟堆内存溢出,emmm需求分析1、数据存储在es,都是单表 涉及表a,b,c,d,e,f 6张表2、每张表数据在百万以上,每个表取几个字段 拼接成一张大报表3、6张表之间对应关系,可能 1条a数据 几千条b数据痛点1、springboot 服务内存 256, new 对象太快 太多 没有足够的空间挪动回收解决:1、利用线程池+redis 异步执行、 poolTaskExecutor.execute(new Runnable() { @Overri

背景:线上报表导出 跑了没1分钟堆内存溢出,emmm
需求分析
1、数据存储在es,都是单表 涉及表a,b,c,d,e,f 6张表
2、每张表数据在百万以上,每个表取几个字段 拼接成一张大报表
3、6张表之间对应关系,可能 1条a数据 几千条b数据

痛点
1、springboot 服务内存 256, new 对象太快 太多 没有足够的空间挪动回收

解决:
1、利用线程池+redis 异步执行、

	poolTaskExecutor.execute(new Runnable() {
			@Override
			public void run() {
				try{
					//redis 加锁
					redisCommonService.set(redisKey,CommonConst.IS_NO);
					
					log.info("子线程执行完毕。。。");
				}catch (Exception e){
					log.error("生成报表数据异常",e);
				}finally {
					//释放锁
					redisCommonService.set(redisKey,CommonConst.IS_YES,6000L);
				}

			}
		});

分析:一个子线程慢慢跑,跑一天都行 redis保证一个用户导出只能跑一个线程,避免子线程太多 导致oom

2、及时释放内存,使用 clear 和弱引用

	public static void batchSave(List<Map<String, Object>> list,Class c){
        
        log.info("总共 需要保存数据有:"+list.size());
        //分次批量插入数据,如果不分次,则可能数据太多导致插入不成功
        int allSize = list.size();  //总记录数
        int perSize = 500;  //每次插入的记录数
        int len = 0;  //插入的次数
        if (allSize % perSize == 0) {  //如果
            // 没有余数
            len = allSize / perSize;
        } else {
            len = allSize / perSize + 1;
        }

        List<Map<String, Object>> tempList = null;
        for (int i = 0; i < len; i++) {
            int startNum = i * perSize;
            int endNum = startNum + perSize;
            tempList = new ArrayList<>();
            WeakReference<Object> obj=new WeakReference<>(tempList);
            for (int index = startNum; index < endNum && index < allSize; index++) {
                tempList.add(list.get(index));
            }
            log.info("本次 是第"+i+"页,批量保存数据有:" + tempList.size());
			
            boolean saveDataBatch = coreService.saveDataBatch(tempList);
            log.info("批量保存返回结果:" + saveDataBatch);
            tempList.clear();
        }
        tempList=null;//htlp gc
    }

分析
1、tempList.clear(); 集合循环利用,避免new 太多
2、WeakReference 加快回收

弱引用测试demo

	private static void test3(){
        Object obj1=new Object();
        WeakReference<Object> obj=new WeakReference<>(obj1);
        obj1=null; //help gc
        //内存够用,手动 gc
        System.gc();
        //内存不够用,自动 gc
        System.out.println(obj1);
        System.out.println(obj.get());
    }

3、由于 数据量大,每个操作分页查 分页存,一批500、存入单表即可

通过以上措施,成功避免了oom、生成30万报表大概 30分钟。___…

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服