[英]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.