【问题标题】:Hibernate out of memory for Query 128MB查询 128MB 的休眠内存不足
【发布时间】:2017-04-12 17:34:31
【问题描述】:

我有一个包含 3,244,977 个寄存器和 154.70 MB 大小的表(来自 phpmyadmin 的数据)

我正在运行一个独立的 Java 应用程序并尝试通过休眠加载所有这些数据。我的域类是:

@Entity
public class Register {

    @Id
    @Column(nullable = false, unique = true, updatable = false)
    private Long userId;

    private Date checked;

    @Column(nullable = false)
    private RegisterType tipo;

    private boolean preLiked = false;
    private boolean preCommented = false;

}

RegisterType 是一个枚举,它在休眠中转换为 int。

如您所见,我的域类并没有那么复杂,考虑到 java 会增加存储在数据库中的数据大小的一些开销,我将堆空间设置为 4GB,然后运行我的应用程序:

java -Xmx4G -cp '....classpath.....' com.tomatechines.bot.Starter

因此,即使对象变大 10 倍,它也应该可以放入堆中。

但我得到 java.lang.OutOfMemoryError: Java heap space

我担心这是其他负载以及大量数据,然后我进行了测试...创建了一个独立的 jar,它只是尝试在没有任何其他变量的情况下加载该表中的所有数据...但是我'我仍然得到异常。

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at java.util.HashMap.resize(HashMap.java:703)
        at java.util.HashMap.putVal(HashMap.java:662)
        at java.util.HashMap.put(HashMap.java:611)
        at org.hibernate.internal.util.collections.IdentityMap.put(IdentityMap.java:94)
        at org.hibernate.engine.internal.StatefulPersistenceContext.addCollection(StatefulPersistenceContext.java:846)
        at org.hibernate.engine.internal.StatefulPersistenceContext.addUninitializedCollection(StatefulPersistenceContext.java:817)
        at org.hibernate.type.CollectionType.getCollection(CollectionType.java:739)
        at org.hibernate.type.CollectionType.resolveKey(CollectionType.java:436)
        at org.hibernate.type.CollectionType.resolve(CollectionType.java:429)
        at org.hibernate.engine.internal.TwoPhaseLoad.doInitializeEntity(TwoPhaseLoad.java:151)
        at org.hibernate.engine.internal.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:125)
        at org.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:1132)
        at org.hibernate.loader.Loader.processResultSet(Loader.java:992)
        at org.hibernate.loader.Loader.doQuery(Loader.java:930)
        at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:336)
        at org.hibernate.loader.Loader.doList(Loader.java:2610)
        at org.hibernate.loader.Loader.doList(Loader.java:2593)
        at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2422)
        at org.hibernate.loader.Loader.list(Loader.java:2417)
        at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:109)
        at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1787)
        at org.hibernate.internal.CriteriaImpl.list(CriteriaImpl.java:363)
        at com.tomatechines.utils.hibernate.GenericDAO.find(GenericDAO.java:183)

同样的查询在不到一秒的时间内在 phpmyadmin 上运行。

在java中运行时它应该变得更大吗? hibernate 使数据库中的事物增长到正常大小的 30 倍?如何在不增大堆空间的情况下处理这个问题?

【问题讨论】:

  • 您正在运行 64 位 jvm?
  • phymyadmin 中的相同命令在一秒钟内从数据库加载 150+mb?也许这只是他们的数量?
  • @Gray 除非您 need userId 有时为空。我穿着这双鞋。但除此之外是的,完全同意
  • 我是nullable = false@Eugene。
  • @Gray 傻我。谢谢

标签: java mysql hibernate out-of-memory heap-memory


【解决方案1】:

对于大约3_300_000 Register 对象,您将绕过160MB 仅针对这些对象的 2 个标题(注册本身、Long、Date 和 RegisterType);甚至不谈论他们的内部——这已经比 postgres 报告更多了;所以是的,您将使用相当多的堆空间。

看起来 Hibernate 出于某种原因将这些条目放在 Map 中,这意味着它将一些实例包装在 LinkedNodeTreeNode 中,这些实例具有 KeyValue,即 至少更多160MB只是用于标题等等......

例如,您可以通过jol 测量每个对象准确需要多少;但这不会给你任何东西——你仍然会因为OutOfMemory而失败。我首先会考虑我为什么需要首先在内存中存储近 350 万个条目;如果有一个令人信服的理由,我会尝试使用较低的 Hibernate。

【讨论】:

  • 你能准确地告诉我什么是 jol 吗?我搜索了谷歌,但它返回了一些法语表达。实际上,我确实需要内存中的所有数据库来进行批处理验证,并且由于我不能仅为堆腾出更多内存,因此我将导致分页过程
  • @RafaelLima 我也想试试这个:docs.jboss.org/hibernate/orm/3.5/api/org/hibernate/…
【解决方案2】:

您可以像这样增加堆大小:https://stackoverflow.com/a/6452812/3978990

或对数据库中的数据进行分页并按部分处理数据。

【讨论】:

    【解决方案3】:

    我正在运行一个独立的 java 应用程序并尝试通过休眠加载所有这些数据...但是我得到 java.lang.OutOfMemoryError: Java heap space

    这是否是预期的取决于您的Register 课程的详细信息。您正在使用休眠加载 300 万个 Register 对象。对于您正在加载的每个userIdLong(它应该是long 原始因为它是nullable = false)和RegisterType 字段,所以还有600 万个对象。我不确定checked 是否也在数据库中——你可能需要说@Transient 或者其他什么也不能加载它。如果已加载,则每个Register 都有另一个对象。我也不确定RegisterType 字段是否被急切地加载,这将是更多的对象。

    因此,根据字段的不同,您可以谈论内存中的 6 到 15+ 百万个对象,并且休眠中有很多开销。它正在尝试将对象添加到作为其缓存一部分的内部身份映射。你肯定需要超过 128mb 的内存才能做到这一点。

    最大的问题是您是否真的需要内存中的所有这些数据来进行处理。您能否改为对数据库进行分页,以便一次只加载 1000 个(假设是)对象?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-16
      • 1970-01-01
      • 2011-08-09
      相关资源
      最近更新 更多