异常java.lang.OutOfMemoryError:使用树映射超过GC限制

3

我在加载Hibernate查询时,一直遇到 java.lang.OutOfMemoryError: GC overhead limit exceeded 错误。

我尝试过几次增加内存,但问题仍然存在。我注意到我的日志似乎指向了一个使用 TreeMap 的方法。我想知道是不是我使用不当导致了内存不足问题。

public List<Item> getProducts() {
    List<ProductListing> productListings = session.createCriteria(ProductListing.class)
    .createAlias("productConfiguration", "productConfiguration")
    .add(Restrictions.eq("productConfiguration.category", category))
    .add(Restrictions.eq("active", true))
    .add(Restrictions.eq("purchased", true)).list();

    Map<String, Item> items = new TreeMap<>();

    productListings.stream().forEach((productListing) -> {
        Item item = productListing.getItem();
        items.put(item.getName(), item);
    });

    return new ArrayList<>(items.values());
}
  • 将值传递到ArrayList中是否安全?

  • 我需要设置ArrayList的大小吗?

我只是想知道我是否做错了什么。看起来没问题,但内存异常表明情况并非如此。

1个回答

3
我将此称为“加载世界”- getProducts()(没有参数)的名称有些不妥 - 因为您没有限制结果集大小,而我们都知道您的Item对象可能很大并具有许多急切加载依赖项(更不用提堆中所有支持Hibernate对象了)。
另一个大问题是,您正在昂贵地将您的脱水实体添加到TreeMap中,调用hashCode()equals(),仅仅为了扔掉键并将值复制到新分配的ArrayList中。
撇开ArrayList的预设大小不足的问题(正确,这并不理想,但应该只会慢一点),为什么要使用TreeMap呢?如果需要进行聚合操作,为什么不让数据库更高效地完成(例如通过GROUP BY name)并使用索引,而不是将其全部拉入映射以进行更慢的重新处理?至少,通过仅获取唯一的Item,您可以跳过映射阶段并直接复制到列表中(根据您的需求,还有更轻量级的可能性)。
我强烈建议使用适当的分析器进行测试。具体来说,它可以帮助您确定急切加载对堆大小的影响。仅仅关闭这个功能可能会使问题更易于管理。
但是,您还需要考虑代码的客户端:谁实际上需要所有这些Item?最有可能没有人需要。

谢谢,我重新设计了一切并将其移入查询中。好多了,问题解决了。 - Code Junkie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接