首页 > 解决方案 > “同步”会影响流的内存占用吗?

问题描述

我们有一个奇怪的 OutOfMemory(堆)案例。鉴于这种方法

private void processRemainingIds(final ITransaction tx) {
    remainingIds.stream()//
        .map(this::getInternalMessage)//
        .filter(this::isMessageNeedsProcessing)//
        .forEach(msg -> registerMessageAsMissing(msg, tx));
}

如果剩余Ids 足够大,则此方法会相当稳定地填满堆。

我希望上述实现会创建大量内部消息,检查并在需要时处理它们,然后丢弃每个对象并偶尔运行 GC。但这不是我们所看到的,而是我们得到

增长堆

OOM的标准问题,即。“有东西抓住了你的物体”我很熟悉。但是为什么getInternalMessage同步会改变任何东西呢?

标签: javastreamjava-streamout-of-memory

解决方案


事实证明,更改为“同步”是一条红鲱鱼,既不是原因也不是解决方案。

原因是 EclipseLink 的 UnitOfWork,默认情况下它包含对每个加载实体的引用。由于getInternalMessage()加载了许多对象,堆慢慢填满。解决方案是使用ReferenceMode.FORCE_WEAK,它只创建对加载实体的弱引用,因此允许它们被 GC'ed。

我推测使getInternalMessage() 同步改变了执行,使得对象加载速度变慢,可能会给 GC 更多时间。这可能导致在同一时间段内的内存倾斜速度较慢,但​​我们后来发现使用同步也遇到了 OOM。


推荐阅读