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

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

如果remainingIds足够大,则此方法会相当稳定地填充堆。
  • getInternalMessage将加​​载“正常”大小的数据模型结构(即,没有blob/clobs等,只有几十个字符串和数字)
  • registerMessageAsMissing在内部调用一个同步方法(也许是相关的)
  • 使getInternalMessage'synchronized'完全改变了内存行为,堆大小不再增加

  • 我希望上面的实现会创建很多内部消息,检查并在需要时对其进行处理,但随后丢弃每个对象并偶尔运行GC。但这不是我们所看到的,相反,我们得到了

    java -  'synchronized'是否会影响流的内存占用量?-LMLPHP

    OOM的标准问题,即我熟悉的是“某些东西在固定住您的对象”。但是,为什么使getInternalMessage同步会发生什么变化呢?

    最佳答案

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

    原因是EclipseLink的UnitOfWork,默认情况下它拥有对每个已加载实体的引用。当getInternalMessage()加载许多对象时,堆慢慢填充了。解决方案是使用ReferenceMode.FORCE_WEAK,它仅创建对已加载实体的弱引用,从而允许对其进行GC处理。

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

    09-05 16:03