Neo4j Java API:运行 多次查询后超出了 GC 开销限制

Neo4j Java API: GC overhead limit exceeded after running multiple queries

我在 Java 中使用 Neo4j 2.3.0。我有 16 GB RAM,运行在 MAC OSX 笔记本电脑上使用“-Xmx12g -Xms12g”作为 VM 参数。

我在 Neo4j 中遇到了“超出 GC 开销限制”的问题 Java API。

为了对大量查询进行实验,我有一个程序可以在不同的 query.db 上打开一个事务,并从我自己的框架中获取答案,该框架包含在一个对象中(它运行s 查询并在文件中打印其 运行ning 时间。

因此,对于 运行 查询,我不使用 Cypher

对于每个查询,我在 query.db 和 data.db 上打开 两个事务 ,初始化我的框架并 运行 它。内存使用量略有增加,“GC 开销”终于发生了。

try (Transaction txG = knowledgeGraph.beginTx()) {
     try (Transaction txQ = queryGraph.beginTx()) {
          MyObj myFramework = new MyObj();
          printTheResultsIntoTheFile(framework.run());
          myFramework =null;
          txQ.success();
          txQ.close();

这些是我为消除此错误所做的一些努力:

  1. 在我使用监控程序转储堆后,我发现这个“org.neo4j.io.pagecache.impl.muninn.MuninnPageCache” 所以,我尝试设置页面缓存大小并将其限制为较小的值:

    dataGraph = new GraphDatabaseFactory().newEmbeddedDatabaseBuilder(MODELGRAPH_DB_PATH) .setConfig(GraphDatabaseSettings.pagecache_memory, "500M").newGraphDatabase();

但是,“内存泄漏”问题依然存在

  1. tx.success()之后,我调用了tx.close()来确保它没有占用内存。

  2. 在使用我的框架(对象)查找查询的答案后,我明确地将其设置为空。 topkFramework=null;

  3. 我调用了System.gc();System.runFinalization();

  4. 我将所有静态变量(如 MyCacheServer 或 MyNeighborIndexer)更改为非静态变量,并且在每个查询中,我都明确了它们,并将它们显式设置为 null。

    queryNodeIdSet.clear(); queryNodeIdSet = null; queryNodeIdSet = new HashSet<Long>();

这是一个猜测(现在没有时间尝试),但我会试一试。 Neo4j 不支持嵌套事务。任何顶级交易(在您的情况下为 txG)都绑定到 ThreadLocal。任何 "nested" 笔交易 (txQ) 都会变成一笔 PlaceboTransaction。因此,对其调用 success()close() 没有任何效果。

因此,当顶级事务打开时,您在子事务中访问的所有内容都保存在内存(堆)中,直到顶级事务完成。我知道这是两个不同的数据库,但仍然是 ThreadLocal.

我认为您每次关闭子级时也应该尝试关闭顶级级。看看有没有帮助。

在深入研究 Neo4j 之后,我发现它与一个接一个地创建大量查询图有关。尽管我在处理每个查询后都调用了 db.shutdown() ,但缓存似乎不会为空。

smallGraph = new GraphDatabaseFactory().newEmbeddedDatabaseBuilder(graphPath)
            .setConfig(GraphDatabaseSettings.pagecache_memory, "240k").newGraphDatabase();

我添加了此配置并将其设置为可能的最小值。现在内存泄漏并不会破坏我的进程。在 运行 大约 1000 个查询之后,它仍然是 运行。早些时候它在 运行 200 次查询后消耗了我所有的内存 (12 GB)。

这是我的堆栈跟踪:

Caused by: java.lang.OutOfMemoryError: GC overhead limit exceeded

    at org.neo4j.io.pagecache.impl.muninn.MuninnPageCache.<init>(MuninnPageCache.java:246)

    at org.neo4j.kernel.impl.pagecache.ConfiguringPageCacheFactory.createPageCache(ConfiguringPageCacheFactory.java:96)

    at org.neo4j.kernel.impl.pagecache.ConfiguringPageCacheFactory.getOrCreatePageCache(ConfiguringPageCacheFactory.java:87)

    at org.neo4j.kernel.impl.factory.PlatformModule.createPageCache(PlatformModule.java:277)

    at org.neo4j.kernel.impl.factory.PlatformModule.<init>(PlatformModule.java:154)

    at org.neo4j.kernel.impl.factory.GraphDatabaseFacadeFactory.createPlatform(GraphDatabaseFacadeFactory.java:181)

    at org.neo4j.kernel.impl.factory.GraphDatabaseFacadeFactory.newFacade(GraphDatabaseFacadeFactory.java:124)

    at org.neo4j.kernel.impl.factory.CommunityFacadeFactory.newFacade(CommunityFacadeFactory.java:43)

    at org.neo4j.kernel.impl.factory.GraphDatabaseFacadeFactory.newFacade(GraphDatabaseFacadeFactory.java:108)

    at org.neo4j.graphdb.factory.GraphDatabaseFactory.newDatabase(GraphDatabaseFactory.java:129)

    at org.neo4j.graphdb.factory.GraphDatabaseFactory.newDatabase(GraphDatabaseFactory.java:117)

    at org.neo4j.graphdb.factory.GraphDatabaseBuilder.newGraphDatabase(GraphDatabaseBuilder.java:185)

    at org.neo4j.graphdb.factory.GraphDatabaseFactory.newEmbeddedDatabase(GraphDatabaseFactory.java:79)

    at org.neo4j.graphdb.factory.GraphDatabaseFactory.newEmbeddedDatabase(GraphDatabaseFactory.java:74)

通常每个 JVM 实例只使用一个 Neo4j 实例。

不幸的是,堆外页面缓存在 JVM 关闭之前不会被释放。

对于与堆相关的部分,您必须确保 shutdown 被调用,并且在调用 System.gc()

您可以重复使用 "smallGraph",清理实例,例如用 MATCH (n) DETACH DELETE n; 然后重新填充它。