代码之家  ›  专栏  ›  技术社区  ›  Nord

使用TDB的apache Jena中的Java OutOfMemoryError

  •  1
  • Nord  · 技术社区  · 7 年前

    我打开TDB Dataset 然后我按带限制和偏移量的页面进行查询。

    我输出文件,每个文件有100000个三元组。

    然而,在第10个文件中,性能下降,在第15个文件中,性能下降了3倍,在第22个文件中,性能下降到1%。

    SELECT DISTINCT ?S ?P ?O WHERE {?S ?P ?O .} LIMIT 100000 OFFSET X

    public boolean copyGraphPage(int size, int page, String tdbPath, String query, String outputDir, String fileName) throws IllegalArgumentException {
            boolean retVal = true;
            if (size == 0) {
                throw new IllegalArgumentException("The size of the page should be bigger than 0");
            }
            long offset = ((long) size) * page;
            Dataset ds = TDBFactory.createDataset(tdbPath);
            ds.begin(ReadWrite.READ);
            String queryString = (new StringBuilder()).append(query).append(" LIMIT " + size + " OFFSET " + offset).toString();
            QueryExecution qExec = QueryExecutionFactory.create(queryString, ds);
            ResultSet resultSet = qExec.execSelect();
            List<String> resultVars;
            if (resultSet.hasNext()) {
                resultVars = resultSet.getResultVars();
                String fullyQualifiedPath = joinPath(outputDir, fileName, "txt");
                try (BufferedWriter bwr = new BufferedWriter(new OutputStreamWriter(new BufferedOutputStream(
                        new FileOutputStream(fullyQualifiedPath)), "UTF-8"))) {
                    while (resultSet.hasNext()) {
                        QuerySolution next = resultSet.next();
                        StringBuffer sb = new StringBuffer();
                        sb.append(next.get(resultVars.get(0)).toString()).append(" ").
                                append(next.get(resultVars.get(1)).toString()).append(" ").
                                append(next.get(resultVars.get(2)).toString());
                        bwr.write(sb.toString());
                        bwr.newLine();
                    }
                    qExec.close();
                    ds.end();
                    ds.close();
                    bwr.flush();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                resultVars = null;
                qExec = null;
                resultSet = null;
                ds = null;
            } else {
                retVal = false;
            }
            return retVal;
        }
    

    空变量在那里,因为我不知道那里是否有可能的泄漏。

    但是,在第22个文件之后,程序失败,并显示以下消息:

    java.lang.OutOfMemoryError: GC overhead limit exceeded
    
        at org.apache.jena.ext.com.google.common.cache.LocalCache$EntryFactory$2.newEntry(LocalCache.java:455)
        at org.apache.jena.ext.com.google.common.cache.LocalCache$Segment.newEntry(LocalCache.java:2144)
        at org.apache.jena.ext.com.google.common.cache.LocalCache$Segment.put(LocalCache.java:3010)
        at org.apache.jena.ext.com.google.common.cache.LocalCache.put(LocalCache.java:4365)
        at org.apache.jena.ext.com.google.common.cache.LocalCache$LocalManualCache.put(LocalCache.java:5077)
        at org.apache.jena.atlas.lib.cache.CacheGuava.put(CacheGuava.java:76)
        at org.apache.jena.tdb.store.nodetable.NodeTableCache.cacheUpdate(NodeTableCache.java:205)
        at org.apache.jena.tdb.store.nodetable.NodeTableCache._retrieveNodeByNodeId(NodeTableCache.java:129)
        at org.apache.jena.tdb.store.nodetable.NodeTableCache.getNodeForNodeId(NodeTableCache.java:82)
        at org.apache.jena.tdb.store.nodetable.NodeTableWrapper.getNodeForNodeId(NodeTableWrapper.java:50)
        at org.apache.jena.tdb.store.nodetable.NodeTableInline.getNodeForNodeId(NodeTableInline.java:67)
        at org.apache.jena.tdb.store.nodetable.NodeTableWrapper.getNodeForNodeId(NodeTableWrapper.java:50)
        at org.apache.jena.tdb.solver.BindingTDB.get1(BindingTDB.java:122)
        at org.apache.jena.sparql.engine.binding.BindingBase.get(BindingBase.java:121)
        at org.apache.jena.sparql.engine.binding.BindingProjectBase.get1(BindingProjectBase.java:52)
        at org.apache.jena.sparql.engine.binding.BindingBase.get(BindingBase.java:121)
        at org.apache.jena.sparql.engine.binding.BindingProjectBase.get1(BindingProjectBase.java:52)
        at org.apache.jena.sparql.engine.binding.BindingBase.get(BindingBase.java:121)
        at org.apache.jena.sparql.engine.binding.BindingBase.hashCode(BindingBase.java:201)
        at org.apache.jena.sparql.engine.binding.BindingBase.hashCode(BindingBase.java:183)
        at java.util.HashMap.hash(HashMap.java:338)
        at java.util.HashMap.containsKey(HashMap.java:595)
        at java.util.HashSet.contains(HashSet.java:203)
        at org.apache.jena.sparql.engine.iterator.QueryIterDistinct.getInputNextUnseen(QueryIterDistinct.java:106)
        at org.apache.jena.sparql.engine.iterator.QueryIterDistinct.hasNextBinding(QueryIterDistinct.java:70)
        at org.apache.jena.sparql.engine.iterator.QueryIteratorBase.hasNext(QueryIteratorBase.java:114)
        at org.apache.jena.sparql.engine.iterator.QueryIterSlice.hasNextBinding(QueryIterSlice.java:76)
        at org.apache.jena.sparql.engine.iterator.QueryIteratorBase.hasNext(QueryIteratorBase.java:114)
        at org.apache.jena.sparql.engine.iterator.QueryIteratorWrapper.hasNextBinding(QueryIteratorWrapper.java:39)
        at org.apache.jena.sparql.engine.iterator.QueryIteratorBase.hasNext(QueryIteratorBase.java:114)
        at org.apache.jena.sparql.engine.iterator.QueryIteratorWrapper.hasNextBinding(QueryIteratorWrapper.java:39)
        at org.apache.jena.sparql.engine.iterator.QueryIteratorBase.hasNext(QueryIteratorBase.java:114)
    
    Disconnected from the target VM, address: '127.0.0.1:57723', transport: 'socket'
    
    Process finished with exit code 255
    

    enter image description here

    enter image description here

    很明显,Jena LocalCache正在填充,我将Xmx更改为2048m,Xms更改为512m,结果相同。没有任何变化。

    我需要更多的内存吗?

    我需要停止程序并分部分执行吗?

    我的问题错了吗?

    偏移量和它有什么关系吗?

    我在一些旧邮件帖子中读到,你可以关闭缓存,但我找不到任何方法。有没有办法关闭缓存?

    我知道这是一个非常困难的问题,但我感谢任何帮助。

    2 回复  |  直到 7 年前
        1
  •  4
  •   AndyS    7 年前

    这是TDB节点缓存-每个数据集本身通常需要1.5G(2G更好)。此缓存在JVM的生命周期内持续存在。

    按照今天的标准,2G的java堆是一个小java堆。如果必须使用小堆,可以尝试在32位模式下运行(在TDB中称为“直接模式”),但性能较低(主要是因为节点缓存较小,并且在该数据集中,您确实有足够的节点导致小缓存的缓存搅动)。

    DISTINCT .

    独特的

    Apache Jena确实优化了(TopN查询)的一些情况,但截断 对于优化,默认值为1000。看见 OpTopN 在代码中。

    否则,它将收集到目前为止看到的所有行。对数据集的遍历越深入,节点缓存中的数据越多,也比独特过滤器中的数据越多。

    是的,更多堆。合理的最小值是每个TDB数据集2G,然后是Java本身需要的任何值(例如,0.5G),再加上您的程序和查询工作区。

        2
  •  0
  •   Irwan Hendra    7 年前

    您似乎在某个地方发生内存泄漏,这只是一个猜测,但请尝试以下操作:

    TDBFactory.release(ds);
    

    裁判: https://jena.apache.org/documentation/javadoc/tdb/org/apache/jena/tdb/TDBFactory.html#release-org.apache.jena.query.Dataset-