簡體   English   中英

使用TDB的Apache Jena中的Java OutOfMemoryError

[英]Java OutOfMemoryError in apache Jena using TDB

嗨,我一直在使用Jena進行項目,現在我正在嘗試查詢Graph以純文件形式存儲,以便使用Hadoop進行批處理。

我打開一個TDB Dataset ,然后按具有LIMIT和OFFSET的頁面進行查詢。

我輸出的文件每個文件有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

查詢頁面后,內存查看器顯示內存使用量的增加:

在此處輸入圖片說明

在此處輸入圖片說明

顯然,Jena LocalCache已滿,我將Xmx更改為2048m,將Xms更改為512m,結果相同。 沒有改變。

我需要更多的內存嗎?

我需要清除一些東西嗎?

我是否需要停止程序並分批執行?

我的查詢錯了嗎?

偏移量與它有關系嗎?

我讀了一些舊郵件,您可以關閉緩存,但找不到任何方法。 有沒有辦法關閉緩存?

我知道這是一個非常困難的問題,但我感謝您的幫助。

顯然,Jena LocalCache正在填滿

這是TDB節點緩存-每個數據集本身通常需要1.5G(最好2G)。 該高速緩存在JVM的生命周期內一直存在。

按照今天的標准,2G的Java堆是很小的Java堆。 如果必須使用較小的堆,則可以嘗試以32位模式(在TDB中稱為“直接模式”)運行,但是性能較低(主要是因為節點緩存較小,並且在此數據集中,您確實有足夠的節點來引起緩存)小型緩存的用戶流失)。

節點緩存是堆耗盡的主要原因,但是每個查詢在DISTINCT查詢正在消耗其他地方的內存。

DISTINCT不一定便宜。 它需要記住已經看到的所有內容,以知道新行是第一次出現還是已經看到。

Apache Jena確實會優化某些情況(一個TopN查詢),但是默認情況下,優化的臨界值為1000。 請參見代碼中的OpTopN

否則,它將收集到目前為止看到的所有行。 您越深入數據集,節點緩存中的內容就越多,DISTINCT過濾器中的內容也就越多。

我需要更多的內存嗎?

是的,更多的堆。 合理的最小值是每個TDB數據集2G,然后是Java本身需要的(例如0.5G),再加上程序和查詢工作區。

您似乎在某處存在內存泄漏,這只是一個猜測,但是請嘗試以下操作:

TDBFactory.release(ds);

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM