【问题标题】:mongo toLIst() java.lang.OutOfMemoryError: Java heap spacemongo toLIst() java.lang.OutOfMemoryError: Java 堆空间
【发布时间】:2021-06-17 21:41:33
【问题描述】:

我尝试从 mongodb 获取一些数据,但我的 k8s pod 命中:

Terminating due to java.lang.OutOfMemoryError: Java heap space

检查堆转储似乎会引起一些麻烦:

try (CloseableIterator<A> iter = 
         mongoTemplate.stream(query(criteria),
                              DocumentAnnotation.class,
                              ANNOTATIONS_COLLECTION_NAME)) {
    return StreamSupport.stream(
        Spliterators.spliteratorUnknownSize(iter, Spliterator.ORDERED), false)
                        .filter(annotation -> isAnnotationAcceptedByFilter(annotation))
                        .collect(Collectors.toList());
}

一般来说,它使用 Mongo 驱动程序流 API 创建一个迭代器,并使用给定的标准迭代数据库返回的所有注释。似乎 Mongo DB 驱动程序正在读取 47427 项的批注(?至少我在堆转储中看到了),尽管事实上大多数都会被 Java 中的过滤器过滤,因此不会返回给客户端,这导致一个问题,因为每个这样的请求都会分配 100MB 的 RAM 来保持这个大容量。

有人知道批量大小是否可配置吗?

谢谢

【问题讨论】:

  • 我想你可能误诊了。该大小的块大小应该没有问题。我怀疑真正的问题是您的过滤器没有过滤掉大部分项目(因此结果列表太大)或者其他地方存在内存泄漏。
  • 但是这个问答是关于设置批量大小的:stackoverflow.com/questions/48072977
  • 这似乎部分解释了这个问题:stackoverflow.com/questions/15516462/…,但仍然不清楚如何解决它......
  • 我看不出它有什么关系。
  • 嗯......那么......那是你的问题。如果过滤后的列表需要 500MB 来存储,那么您需要那么多内存。或者您需要更改您的应用程序设计/逻辑,以便您根本不需要创建列表。 (这与驱动程序使用的批量大小无关。)

标签: java mongodb


【解决方案1】:

根据您在 cmets 中所说的话,我的看法是您误诊了问题。批量大小(或您所说的“批量大小”)不是问题,更改 Mongo 驱动程序的内部批量大小不会解决问题。真正的问题是,即使在过滤之后,您使用流创建的列表对于您正在使用的 Java 堆大小而言太大

有两种可能的方法来解决这个问题:

  • 不要将注释放入List,而是迭代流并在获得注释时对其进行处理。

  • 想办法批量提取注释。然后获取每批注释的单独列表。

(在其他情况下,我建议尝试在 MongoDB 查询本身中进行过滤。但这无助于解决您的 OOME 问题。)

但如果您需要同时在内存中的所有注释来处理它们,那么您唯一可行的选择就是获得更多内存

【讨论】:

    猜你喜欢
    • 2021-09-09
    • 2011-10-24
    • 2017-05-13
    • 1970-01-01
    • 2011-11-05
    • 2013-11-18
    • 2010-10-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多