在无限流中使用 Integer 捕获闭包的 Lambda 会抛出 OutOfMemoryError

Lambda capturing closure with Integer in endless stream throws OutOfMemoryError

提问人:J.J. Beam 提问时间:11/18/2021 最后编辑:J.J. Beam 更新时间:11/18/2021 访问量:33

问:

低于 100% 的代码抛出java.lang.OutOfMemoryError

Set<Integer> set = new HashSet<>();
    new Random().ints(10_000_000,
            Integer.MIN_VALUE,
            Integer.MAX_VALUE)
            .forEach(
                    v -> {
                        if(set.contains(v)){
                            System.out.println(v);
                        }else{
                            set.add(v);
                        }
                    }
            );

AFAIK 这是因为 lambda 捕获带有上下文的整数?谁能解释一下这里到底发生了什么?

Java Lambda 闭包

评论

0赞 geobreze 11/18/2021
你的 java 版本是什么?我有 openjdk 版本“11.0.12” 2021-07-20 OpenJDK 运行时环境自制软件(内部版本 11.0.12+0) OpenJDK 64 位服务器虚拟机自制软件(内部版本 11.0.12+0,混合模式)。当我使用堆运行此代码时,永远不会高于 90mb-Xmx128m
0赞 J.J. Beam 11/18/2021
对不起,我编辑了代码示例,请尝试

答:

1赞 geobreze 11/18/2021 #1

在您的代码中,您可以从方法访问。本地堆栈是 GC 根,因此 GC 无法收集它。Setmain

因此,您正在向集合中添加无法收集的元素。set 需要额外的内存来存储元素。

在我的 PC 上,在没有 OOM 的情况下运行此程序需要大约 600 MB 的堆。

这是在我的电脑上运行的这个程序的堆转储。

heap dump

我尝试了与香草循环相同的代码并得到了相同的结果。for

因此,您只需要为应用程序添加更多内存即可。例如,将堆大小设置为 1 GB。-Xmx1g

评论

0赞 J.J. Beam 11/18/2021
实际上我是从单元测试开始代码的,它和从 main 方法一样吗?
0赞 geobreze 11/18/2021
是的,从单元测试开始时,您的代码也可以从本地堆栈访问。您可以在 surefire 插件的配置中设置内存设置 stackoverflow.com/a/7579853/4655217