static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 2, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(5000), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
public static void main(String[] args) {
List<Map<String, String>> list = new ArrayList<>();
// add 5000 次
list.add(new HashMap<>(16));
list.forEach(l -> CompletableFuture.runAsync(() -> {
System.out.println(l.get("xxx"));
System.out.println(l.get("yyy"));
// 又臭又长的代码 耗时 1s
}, threadPoolExecutor));
// 问:此时阻塞队列中任务内存占用主要来源于哪里?
// 是遍历 list 出来的每个元素对象的占用内存吗?
// 业务逻辑代码的长短 /复杂度会影响内存占用吗?
}
1
bootvue 2022-12-14 17:10:52 +08:00
没有大佬 可以配合 jprofile 分析下
|
2
guyeu 2022-12-14 17:22:33 +08:00
了解下引用和对象的概念呗
|
3
wangxin3 OP @guyeu #2 原文:“了解下引用和对象的概念呗”
====== 回复:想了想,list 对象在进入阻塞队列之前已经存在于内存中了,所以线程池中的内存占用主要是来源于对象的地址,以及方法的地址?不知道是不是这样理解 |
5
7911364440 2022-12-14 17:41:48 +08:00
线程池的内存占用取决于线程的数量,线程的内存占用取决于 run()方法中申请的内存空间,其实就是看你那段 "又臭又长的代码 耗时 1s" 的逻辑
|
6
wangxin3 OP @7911364440 #5 原文:“线程池的内存占用取决于线程的数量,线程的内存占用取决于 run()方法中申请的内存空间,其实就是看你那段 "又臭又长的代码 耗时 1s" 的逻辑”
====== 回复:懂了,那按理来说线程池导致的 oom ,唯一的原因可能就是没有设置阻塞队列的长度?因为如果设置了长度,合理设置了 corePoolSize 、maximumPoolSize ,那么线程池多个线程在运行同一个方法时,因为单个方法的内存占用量是固定的,corePoolSize 是固定的,所以可以说线程池的内存占用量就是固定的。 线程池内存占用量 = corePoolSize * 单个方法的内存占用量(阻塞队列还没满时) |
7
Yuesh1 2022-12-14 18:37:41 +08:00
突然想到,线程池本身也是一个对象,也需要内存占用,应该也有少量的内存消耗。
我理解的线程池 oom ,在合理设置了参数后,应该就是阻塞队列的 maxSize = Integer.MAX_VALUE 所导致的 期待其他大佬的见解 |
8
optional 2022-12-14 19:11:57 +08:00
你这里每个 map 对象每个对象都被 list 引用了,没有释放的机会;
另外()->{}会创建一个闭包对象。 |
9
chendy 2022-12-14 19:58:29 +08:00
> 此时阻塞队列中任务内存占用主要来源于哪里?
来源于 '阻塞别列中任务占用的内存' > 是遍历 list 出来的每个元素对象的占用内存吗? 是 '每个元素对象的的占用的内存' > 业务逻辑代码的长短 /复杂度会影响内存占用吗? 会,越慢堆积任务越多,越复杂当然也多 |
10
liprais 2022-12-14 20:30:23 +08:00 via iPhone
不要打印到标准输出,那上面有个锁
|
11
imv2er 2022-12-14 20:52:10 +08:00
我的能算标准答案么
//此时阻塞队列中任务内存占用主要来源于哪里? map 中的 kv 元素数量 // 是遍历 list 出来的每个元素对象的占用内存吗? 是的 // 业务逻辑代码的长短 /复杂度会影响内存占用吗 会 ,因为这些逻辑代码中间几乎肯定会产生很多临时对象, 当然回收也很快。 |
12
wangxin3 OP |