You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java 19并行流中skip()为何导致8GB内存下出现OOM?

为什么添加skip(2)会导致并行流内存溢出(OOM)?

现象描述

在Java 19环境、8GB内存配置下,以下带skip(2)的并行IntStream代码会触发OOM:

IntStream
.iterate(0, i -> i + 1)
.skip(2)
.limit(10_000_000)
.filter(i -> checkSum(i) <= 20)
.parallel()
.count();

但移除skip(2)后,代码可以正常运行不会出现OOM:

IntStream
.iterate(0, i -> i + 1)
//.skip(2)
.limit(10_000_000)
.filter(i -> checkSum(i) <= 20)
.parallel()
.count();

其中checkSum方法实现如下:

public static long checkSum(long n) {
    long result = 0;
    long remaining = n;
    while (0 < remaining) {
        long remainder = remaining % 10;
        result += remainder;
        remaining = (remaining - remainder) / 10;
    }
    return result;
}

核心原因分析

  • IntStream.iterate生成的是无序无限流:和IntStream.range()这种有明确范围的有序流不同,iterate生成的流没有固定边界,并行处理时无法直接拆分为均匀的子任务段。
  • skip(2)破坏了limit的任务分配优化:
    无skip时,并行流处理iterate+limit组合时,内部会尝试给每个线程分配大致等量的连续数值任务,避免任务过度拆分。
    但添加skip(2)后,流结构变为skip -> limit,为了保证准确跳过前2个元素,每个线程在处理limit内的元素前,必须先处理并丢弃前2个元素。这导致原本的批量任务分配逻辑失效,只能生成大量细小的任务。
  • 任务队列堆积占用内存:
    并行流依赖ForkJoinPool处理任务,skip+limit的组合会让ForkJoinPool不断拆分出大量小任务。当任务生成速度远快于线程处理速度时,这些待处理任务会在队列中大量堆积,占用的内存持续增长,最终触发OOM。
  • checkSum方法加速了内存溢出:checkSum是相对耗时的计算操作,线程处理单个任务的时间变长,进一步加剧了任务队列的堆积速度,更快耗尽内存。

内容的提问来源于stack exchange,提问作者mmirwaldt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 20:35:17