Neo4j在节点/关系创建时嵌入内存不足

时间:2014-07-02 10:51:40

标签: java neo4j out-of-memory

我一直在调查Neo4j的生物信息学问题。我创建了大约20000个节点。这些节点 应该与每个约100个节点相关。

我想将Java核心API与嵌入式Neo4j数据库一起使用,如[Java教程]中所述 (http://docs.neo4j.org/chunked/milestone/tutorials-java-embedded-hello-world.html

在添加派生节点和关系之前,我首先要查询数据库以获取现有节点。

我很快就会遇到过多的内存消耗。我在这里附上一个使Neo4J崩溃的Java方法。 拜托,您能否给我一个如何解决这个内存问题的提示。解决这种情况的最佳做法是什么?

我附加内存使用情况图表(来自VisualVM的快照)以说明内存使用量enter image description hereenter image description hereenter image description here

配置:

  Platform : Windows-7 win32,  java-1.7.0_51 (Program arguments -Xms512m -Xmx1024m)
  neo4j.properties
    use_memory_mapped_buffers=true
    neostore.nodestore.db.mapped_memory=100M
    neostore.relationshipstore.db.mapped_memory=150M
    neostore.propertystore.db.mapped_memory=150M
    neostore.propertystore.db.strings.mapped_memory=150M
    neostore.propertystore.db.arrays.mapped_memory=150M

  neo4j-wrapper.conf
    wrapper.java.additional=-XX:+UseConcMarkSweepGC
    wrapper.java.additional=-XX:+CMSClassUnloadingEnabled
    wrapper.java.initmemory=512
    wrapper.java.maxmemory=1024

提前致谢, 最好的问候

代码:值的限制因人而异,平均值应在100左右。

static void stackoverflowNativeAPIMemoryIssue() {
    String DB_PATH = "C:/neo4j/Neo4j-2.1.2/data/graph.db";
    GraphDatabaseService db = new GraphDatabaseFactory()
        .newEmbeddedDatabase(DB_PATH);        
    // *** query
    String query = "match (n:ExistingNode) return n;";            
    ExecutionEngine engine = new ExecutionEngine(db);        
    ExecutionResult result;        
    Label labelFrom = DynamicLabel.label("From");        
    result = engine.execute(query);        
    Iterator<Node> n_column = result.columnAs("n");
    Node nodeFrom = null;
    Relationship relationship = null;        
    int count = 0;        
    int i = 0;
    for (Node nodeTo : IteratorUtil.asIterable(n_column)) {
      // loop which makes the code break!
      //for (i = 0; i < 5; i++) {
        try (Transaction tx = db.beginTx()) {
          ++count;
          nodeFrom = db.createNode(labelFrom);
          nodeFrom.setProperty("name", "name-" + count + "-" + i);

          relationship = nodeFrom.createRelationshipTo(nodeTo,
              Relation.MY_RELATION);
          relationship.setProperty("name", "relation-" + count
              + "- " + i);
          tx.success();
        }    
      //}
    }
    db.shutdown();
    }

没有循环:程序一直运行到最后......

循环5 - &gt;内存扩展,但进程终止OK。

循环10次 - &gt;内存不足 没有节点,没有创建关系,尽管应该在每个节点和关系创建上触发事务。

Exception in thread "GC-Monitor" Exception in thread "main" java.lang.OutOfMemoryError: 
Java heap space
at java.lang.AbstractStringBuilder.append(Unknown Source)
at java.lang.StringBuilder.append(Unknown Source)
at org.neo4j.kernel.impl.cache.MeasureDoNothing.run(MeasureDoNothing.java:84)
java.lang.OutOfMemoryError: Java heap space
at org.neo4j.kernel.impl.util.VersionedHashMap.put(VersionedHashMap.java:185)
at java.util.Collections$SetFromMap.add(Unknown Source)
at org.neo4j.kernel.impl.util.DiffSets.add(DiffSets.java:100)
at org.neo4j.kernel.impl.api.state.TxStateImpl.nodeDoCreate(TxStateImpl.java:363)
at org.neo4j.kernel.impl.api.StateHandlingStatementOperations.nodeCreate(StateHandlingStatementOperations.java:101)
at org.neo4j.kernel.impl.api.ConstraintEnforcingEntityOperations.nodeCreate(ConstraintEnforcingEntityOperations.java:390)
at org.neo4j.kernel.impl.api.LockingStatementOperations.nodeCreate(LockingStatementOperations.java:208)
at org.neo4j.kernel.impl.api.OperationsFacade.nodeCreate(OperationsFacade.java:500)
at org.neo4j.kernel.InternalAbstractGraphDatabase.createNode(InternalAbstractGraphDatabase.java:1125)

3 个答案:

答案 0 :(得分:1)

我遇到了一个运行很长事务的程序的类似问题。

我的程序基本上是逐行解析一个大的CSV文件,并为它解析的每一行注入节点和关系。这个big while循环包含在一个Transaction块中。

我的内存泄漏就像你描述的那样。

我发现,使用VisualVM时,当while循环结束时,内存堆大小大量下降。所以我想知道:“那个循环中永远存在的对象是什么?”答案是Transaction对象。

所以我修补了我的程序,为文件解析循环的每次迭代创建一个Transaction,虽然这降低了解析的性能,但它解决了内存泄漏,在运行一些迭代后堆大小现在稳定了。 / p>

我希望有所帮助。

如果Neo4j专家能够揭示交易泄密的原因,那将非常感激。

答案 1 :(得分:0)

请注意,在Windows平台上,mapped_memory是JVM堆的一部分。总共有700M分配给映射内存,最大堆大小为1G - 剩下的内存更少。

增加最大堆或缩小映射内存。

答案 2 :(得分:0)

上面的代码存在更广泛的问题。

result = engine.execute(query);

本身应该在交易中,至少在概念上。它返回一个延迟计算的迭代器,每次调用此迭代器都需要对它返回的节点进行读锁定。因此,您实际上是在尝试将作为一个打开事务的结果的节点传递给编辑它们的第二个事务。

假设在代码中间,在生成迭代器之后,我做了第三个事务,删除了所有节点,然后会发生什么?

基本上,您不应该尝试将节点对象从一个事务传递到另一个事务。 Neo4j是一个服务器,并且在您的交易关闭之后,但在第二个交易打开之前,不能假设没有其他用户会编辑这些用户。

我怀疑在服务器端,死锁解析例程的整个平移正在开始行动,以处理在同一节点对象上有多个打开事务的事实,其中至少有一个是写事务。这可能是您感知泄漏的原因。

尝试将执行引擎代码放入事务中,然后在单个事务中迭代循环。在单个事务中创建几千个实体是完全没问题的,并且具有最小的堆空间开销。