使用completionservice线程池不当,导致OOM

问题来源

https://mp.weixin.qq.com/s/XPInv8Ecwt_UANR7CAq7BQ

  • 问题
    • 向CompletionService提交任务,因为是无返回值不关心它的最终结果,导致没有正确使用take方法取出完成的任务(线程池完成的任务会丢到链表型队列里),因为链表是无界的,所以链表型的队列也是无界队列。久而久之,链表就会存放很多的任务对象,最终oom。
    • 正确的做法是不管是有返回值还是无返回值,使用CompletionService线程池,都要调用take方法取出完成后的任务。

代码模拟

  • 首先,service层去写个方法,这个方法利用 CompletionService 去提交一个无返回值的任务。不要去调用take()方法。
package com.hjx.completionserviceoom.service;  
  
import org.springframework.stereotype.Service;  
import java.util.concurrent.CompletionService;  
import java.util.concurrent.Executor;  
import java.util.concurrent.ExecutorCompletionService;  
import java.util.concurrent.Executors;  
  
@Service  
public class CompletionServiceService {  
  
    private static Executor executor = Executors.newFixedThreadPool(10);  
    private static CompletionService<String> service = new ExecutorCompletionService<>(executor);  
  
    public String test1(){  
        for (int i = 0; i < 50; i++) {  
            service.submit(()->{  
                return "HelloWorld--" + Thread.currentThread().getName();  
            });  
        }  
        return "";  
    }  
}
  • controller层去调用service层的方法
package com.hjx.completionserviceoom.controller;  
  
import com.hjx.completionserviceoom.service.CompletionServiceService;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.web.bind.annotation.RequestMapping;  
import org.springframework.web.bind.annotation.RestController;  
  
  
import java.util.concurrent.atomic.AtomicInteger;  
  
  
@RestController  
public class CompletionServiceController {  
  
    private static AtomicInteger count = new AtomicInteger();  
    @Autowired  
    CompletionServiceService completionServiceService;  
  
    @RequestMapping("/test1")  
    public String test1(){  
        completionServiceService.test1();  
        int num = count.incrementAndGet();  
        return num+"";  
    }  
}

在这里插入图片描述

命令:
-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\heapdump.hprof
其中 D:\heapdump.hprof 是dump文件生成的路径

  • 浏览器无限刷新,直到oom 在这里插入图片描述

执行了948次,终于转不动了,按得我手酸emmm,建议20m调成17m左右,不能太小,起不来程序。或者service层for次数调大一点。

在这里插入图片描述oom了,jconsole 断开了链接

在这里插入图片描述

终于拿到内存dump文件
在这里插入图片描述

排查思路

开始排查

打开mat分析工具,打开heapdump.hprof文件
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

总结

mat的分析,最终发现了是ExecutorComopletionService的completionQueue属性占用了大量的内存,导致oom。定位到了,然后就要去看源码了。

代码

https://github.com/HuangJiaxin8/completionservice-oom

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值