我们有一个OutOfMemory(堆)的怪异案例。有了这种方法
private void processRemainingIds(final ITransaction tx) {
remainingIds.stream()//
.map(this::getInternalMessage)//
.filter(this::isMessageNeedsProcessing)//
.forEach(msg -> registerMessageAsMissing(msg, tx));
}
如果剩余Ids足够大,则此方法会相当稳定地填充堆。
getInternalMessage
将加载“正常”大小的数据模型结构(即,没有blob / clob等,只有几十个字符串和数字)registerMessageAsMissing
内部调用一个同步方法(也许是相关的)getInternalMessage
“同步”完全改变了内存行为,堆大小不再增加 我希望上面的实现会创建很多内部消息,检查并在需要时对其进行处理,但是随后丢弃每个对象并偶尔运行GC。但这不是我们所看到的,相反,我们得到了
OOM的标准问题,即我熟悉的是“某些东西在固定住您的对象”。但是,为什么使getInternalMessage
同步会发生任何变化?
答案 0 :(得分:0)
结果证明,更改为“同步”是一个红鲱鱼,既不是原因,也不是解决方案。
原因是EclipseLink的UnitOfWork,默认情况下,它包含对每个已加载实体的引用。 getInternalMessage()
正在加载许多对象时,堆慢慢填充了。解决方案是使用ReferenceMode.FORCE_WEAK
,它只会创建对已加载实体的弱引用,从而允许对其进行GC处理。
我猜想使getInternalMessage()
同步会改变执行,从而使对象加载速度变慢,也许会给GC多一点时间。在同一时间段内,这可能会导致内存倾斜速度变慢,但是后来我们发现在同步的情况下,我们也遇到了OOM。