Java Neo4J内存溢出问题

3

这有点类似于Neo4j内存不足问题

但这个问题已经过时了,而且据我所知,解决方案也是过时的。

所以我试图插入大约10万个节点和550万个关系(实际上我缩小了数据集,现在更像是不到10万个节点和280万个关系)。

一段时间后,它会耗尽内存,然后我会收到以下异常:

Exception in thread "GC-Monitor" java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOfRange(Unknown Source)
    at java.lang.String.<init>(Unknown Source)
    at java.lang.StringBuilder.toString(Unknown Source)
    at org.neo4j.kernel.impl.util.StringLogger$ActualStringLogger.logMessage(StringLogger.java:276)
    at org.neo4j.kernel.impl.cache.MeasureDoNothing.run(MeasureDoNothing.java:85)
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.util.LinkedList.addBefore(Unknown Source)
    at java.util.LinkedList.add(Unknown Source)
    at org.neo4j.kernel.impl.nioneo.store.IdGeneratorImpl.freeId(IdGeneratorImpl.java:291)
    at org.neo4j.kernel.impl.nioneo.store.CommonAbstractStore.freeId(CommonAbstractStore.java:382)
    at org.neo4j.kernel.impl.nioneo.xa.WriteTransaction.doRollback(WriteTransaction.java:315)
    at org.neo4j.kernel.impl.transaction.xaframework.XaTransaction.rollback(XaTransaction.java:278)
    at org.neo4j.kernel.impl.transaction.xaframework.XaResourceManager.rollback(XaResourceManager.java:518)
    at org.neo4j.kernel.impl.transaction.xaframework.XaResourceHelpImpl.rollback(XaResourceHelpImpl.java:111)
    at org.neo4j.kernel.impl.transaction.TransactionImpl.doRollback(TransactionImpl.java:558)
    at org.neo4j.kernel.impl.transaction.TxManager.rollback(TxManager.java:610)
    at org.neo4j.kernel.impl.transaction.TransactionImpl.rollback(TransactionImpl.java:129)
    at org.neo4j.kernel.TopLevelTransaction.finish(TopLevelTransaction.java:119)
    at sqlToGraph.SqlToGraph.main(SqlToGraph.java:81)

我尝试将-Xmx1500m传递给Java,这是我能传递的极限,因为在此之前它会抱怨无法分配堆空间。这样做可以使程序运行时间更长,但仍然无法完成。

以下是略作编辑的代码:

/* Postgres query and setup stuff cut */
Transaction tx = graphDb.beginTx();
try {
    while (rs.next()) {
        user_lo = rs.getInt(1);
        user_hi = rs.getInt(2);
        n_lo = getOrCreate(user_lo, graphDb);
        n_lo.setProperty("user_id", user_lo);
        n_lo.setProperty("total", rs.getInt(3));
        n_hi = getOrCreate(user_hi, graphDb);
        n_hi.setProperty("user_id", user_hi);
        n_hi.setProperty("total", rs.getInt(4));
        relationship = n_lo.createRelationshipTo(n_hi, RelTypes.PLAYED_WITH);
        relationship.setProperty("mean_percent", rs.getDouble(5));
    }
    tx.success();
} finally {
    tx.finish();
}
graphDb.shutdown();

如果您使用的是64位系统和JVM,如果您认为您的算法无法通过减少内存使用来改进,那么可以尝试将堆设置得更大。 - AndreiM
你提交事务的频率是多少?我们可以看一下你的代码吗? - Mattias Finné
不是很经常吗?像,一次吗?那是我的问题吗?已添加代码。 - Tom Carrick
这确实是个问题。交易数据会一直保存在内存中,直到提交。每一万次左右就要提交(重新启动事务)。 - Mattias Finné
我只需保持计数器并在每x次迭代中随机调用提交,还是需要更多的操作?如果可以的话,请将其编写为适当的答案,以便我可以考虑它(如果它有效)。 - Tom Carrick
显示剩余2条评论
2个回答

11

在这里添加另一个答案。所以,根据代码,问题在于您从未提交事务。除非提交,否则事务数据将保留在内存中,因此所有创建的节点和关系都将停留在内存中等待提交,这就是为什么最终会出现OOM的原因。

我建议修改代码如下:

/* 截取Postgres查询和设置部分 */
Transaction tx = graphDb.beginTx();
try {
    for (int i = 0; rs.next(); i++) {
        user_lo = rs.getInt(1);
        user_hi = rs.getInt(2);
        n_lo = getOrCreate(user_lo, graphDb);
        n_lo.setProperty("user_id", user_lo);
        n_lo.setProperty("total", rs.getInt(3));
        n_hi = getOrCreate(user_hi, graphDb);
        n_hi.setProperty("user_id", user_hi);
        n_hi.setProperty("total", rs.getInt(4));
        relationship = n_lo.createRelationshipTo(n_hi, RelTypes.PLAYED_WITH);
        relationship.setProperty("mean_percent", rs.getDouble(5));
// 每隔一段时间提交一次以释放内存。 if ( i > 0 && i % 10000 == 0 ) { tx.success(); tx.finish(); tx = graphDb.beginTx(); } } tx.success(); } finally { tx.finish(); } graphDb.shutdown();

0
如果将事务拆分不可行,因为您依赖于单个事务的原子性保证,那么另一个选择可能是简化数据模型,例如减少添加到节点/关系的属性数量。
在我们的情况下,我们可以通过省略保存默认值或零的属性来解决OOM问题。

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