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();
这些是我为消除此错误所做的一些努力:
在我使用监控程序转储堆后,我发现这个“org.neo4j.io.pagecache.impl.muninn.MuninnPageCache”
所以,我尝试设置页面缓存大小并将其限制为较小的值:
dataGraph = new GraphDatabaseFactory().newEmbeddedDatabaseBuilder(MODELGRAPH_DB_PATH)
.setConfig(GraphDatabaseSettings.pagecache_memory, "500M").newGraphDatabase();
但是,“内存泄漏”问题依然存在
在tx.success()
之后,我调用了tx.close()
来确保它没有占用内存。
在使用我的框架(对象)查找查询的答案后,我明确地将其设置为空。 topkFramework=null;
我调用了System.gc();
和System.runFinalization();
我将所有静态变量(如 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;
然后重新填充它。
我在 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();
这些是我为消除此错误所做的一些努力:
在我使用监控程序转储堆后,我发现这个“org.neo4j.io.pagecache.impl.muninn.MuninnPageCache” 所以,我尝试设置页面缓存大小并将其限制为较小的值:
dataGraph = new GraphDatabaseFactory().newEmbeddedDatabaseBuilder(MODELGRAPH_DB_PATH) .setConfig(GraphDatabaseSettings.pagecache_memory, "500M").newGraphDatabase();
但是,“内存泄漏”问题依然存在
在
tx.success()
之后,我调用了tx.close()
来确保它没有占用内存。在使用我的框架(对象)查找查询的答案后,我明确地将其设置为空。
topkFramework=null;
我调用了
System.gc();
和System.runFinalization();
我将所有静态变量(如 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;
然后重新填充它。