在 运行 Solr 查询期间,幸存世代不断增加
Surviving generations keep increasing while running Solr query
我正在使用 jSolr (7.4) 测试查询,因为我认为它会导致我的程序发生内存泄漏。但是不确定是不是内存泄露,求教!
此方法在我的索引程序 运行ning 时间内被多次调用(应该 运行 周/月没有任何问题)。这就是为什么我在使用 Netbeans Profiler 分析的循环中对其进行测试的原因。
如果我简单地从给定索引中的所有文档(有 33k)中检索 id :
public class MyIndex {
// This is used as a cache variable to avoid querying the index everytime the list of documents is needed
private List<MyDocument> listOfMyDocumentsAlreadyIndexed = null;
public final List<MyDocument> getListOfMyDocumentsAlreadyIndexed() throws SolrServerException, HttpSolrClient.RemoteSolrException, IOException {
SolrQuery query = new SolrQuery("*:*");
query.addField("id");
query.setRows(Integer.MAX_VALUE); // we want ALL documents in the index not only the first ones
SolrDocumentList results = this.getSolrClient().
query(query).getResults();
/**
* The following was commented for the test,
* so that it can be told where the leak comes from.
*
*/
// listOfMyDocumentsAlreadyIndexed = results.parallelStream()
// .map((doc) -> { // different stuff ...
// return myDocument;
// })
// .collect(Collectors.toList());
return listOfMyDocumentsAlreadyIndexed;
/** The number of surviving generations
* keeps increasing whereas if null is
* returned then the number of surviving
* generations is not increasing anymore
*/
}
我从分析器中得到这个(在将近 200 运行s 之后可以为我的程序模拟一年的 运行 时间):
存活最多的对象是String
:
在查询索引中的所有文档时,存活代数的增加是否是预期的行为?
如果是这样的话,这是我在生产服务器上一段时间后遇到的 "OOM Java heap space" 错误的根本原因,因为它似乎来自堆栈跟踪:
Exception in thread "Timer-0" java.lang.OutOfMemoryError: Java heap space
at org.noggit.CharArr.resize(CharArr.java:110)
at org.noggit.CharArr.reserve(CharArr.java:116)
at org.apache.solr.common.util.ByteUtils.UTF8toUTF16(ByteUtils.java:68)
at org.apache.solr.common.util.JavaBinCodec.readStr(JavaBinCodec.java:868)
at org.apache.solr.common.util.JavaBinCodec.readStr(JavaBinCodec.java:857)
at org.apache.solr.common.util.JavaBinCodec.readObject(JavaBinCodec.java:266)
at org.apache.solr.common.util.JavaBinCodec.readVal(JavaBinCodec.java:256)
at org.apache.solr.common.util.JavaBinCodec.readSolrDocument(JavaBinCodec.java:541)
at org.apache.solr.common.util.JavaBinCodec.readObject(JavaBinCodec.java:305)
at org.apache.solr.common.util.JavaBinCodec.readVal(JavaBinCodec.java:256)
at org.apache.solr.common.util.JavaBinCodec.readArray(JavaBinCodec.java:747)
at org.apache.solr.common.util.JavaBinCodec.readObject(JavaBinCodec.java:272)
at org.apache.solr.common.util.JavaBinCodec.readVal(JavaBinCodec.java:256)
at org.apache.solr.common.util.JavaBinCodec.readSolrDocumentList(JavaBinCodec.java:555)
at org.apache.solr.common.util.JavaBinCodec.readObject(JavaBinCodec.java:307)
at org.apache.solr.common.util.JavaBinCodec.readVal(JavaBinCodec.java:256)
at org.apache.solr.common.util.JavaBinCodec.readOrderedMap(JavaBinCodec.java:200)
at org.apache.solr.common.util.JavaBinCodec.readObject(JavaBinCodec.java:274)
at org.apache.solr.common.util.JavaBinCodec.readVal(JavaBinCodec.java:256)
at org.apache.solr.common.util.JavaBinCodec.unmarshal(JavaBinCodec.java:178)
at org.apache.solr.client.solrj.impl.BinaryResponseParser.processResponse(BinaryResponseParser.java:50)
at org.apache.solr.client.solrj.impl.HttpSolrClient.executeMethod(HttpSolrClient.java:614)
at org.apache.solr.client.solrj.impl.HttpSolrClient.request(HttpSolrClient.java:255)
at org.apache.solr.client.solrj.impl.HttpSolrClient.request(HttpSolrClient.java:244)
at org.apache.solr.client.solrj.SolrRequest.process(SolrRequest.java:194)
at org.apache.solr.client.solrj.SolrClient.query(SolrClient.java:942)
at org.apache.solr.client.solrj.SolrClient.query(SolrClient.java:957)
将堆 space ("-Xmx") 从 8GB 增加到任何更大的值肯定会解决问题还是只是推迟它?可以做些什么来解决这个问题?
几个小时后编辑
如果从被测方法返回 null
(getListOfMyDocumentsAlreadyIndexed
) 那么在整个测试过程中幸存世代的数量保持稳定:
所以即使我没有使用这个测试的查询结果(因为我只想关注泄漏发生的地方)它看起来像返回一个实例变量(即使它是空的)不是一个好主意。我会尝试删除它。
稍后编辑
我注意到当我分析 "defined classes" ("focused (instrumented)") 时,遥测选项卡中的幸存世代仍在增加,而分析 "All classes" ("General (sampled)").所以我不确定它是否解决了问题:
非常感谢任何提示:-)
问题源于以下行:
query.setRows(Integer.MAX_VALUE);
根据这篇文章不应该这样做:
The rows parameter for Solr can be used to return more than the default of 10 rows. I have seen users successfully set the rows parameter to 100-200 and not see any issues. However, setting the rows parameter higher has a big memory consequence and should be avoided at all costs.
因此,通过 this solr article on pagination 之后的 200 个文档块检索文档解决了问题:
SolrQuery q = (new SolrQuery(some_query)).setRows(r).setSort(SortClause.asc("id"));
String cursorMark = CursorMarkParams.CURSOR_MARK_START;
boolean done = false;
while (! done) {
q.set(CursorMarkParams.CURSOR_MARK_PARAM, cursorMark);
QueryResponse rsp = solrServer.query(q);
String nextCursorMark = rsp.getNextCursorMark();
doCustomProcessingOfResults(rsp);
if (cursorMark.equals(nextCursorMark)) {
done = true;
}
cursorMark = nextCursorMark;
}
请注意:setRows
中的文档不应超过 200 个,否则内存泄漏仍然会发生(例如,500 个文档确实会发生)。
现在,分析器在存活世代方面给出了更好的结果,因为它们不再随时间增加。
但是该方法要慢得多。
我正在使用 jSolr (7.4) 测试查询,因为我认为它会导致我的程序发生内存泄漏。但是不确定是不是内存泄露,求教!
此方法在我的索引程序 运行ning 时间内被多次调用(应该 运行 周/月没有任何问题)。这就是为什么我在使用 Netbeans Profiler 分析的循环中对其进行测试的原因。
如果我简单地从给定索引中的所有文档(有 33k)中检索 id :
public class MyIndex {
// This is used as a cache variable to avoid querying the index everytime the list of documents is needed
private List<MyDocument> listOfMyDocumentsAlreadyIndexed = null;
public final List<MyDocument> getListOfMyDocumentsAlreadyIndexed() throws SolrServerException, HttpSolrClient.RemoteSolrException, IOException {
SolrQuery query = new SolrQuery("*:*");
query.addField("id");
query.setRows(Integer.MAX_VALUE); // we want ALL documents in the index not only the first ones
SolrDocumentList results = this.getSolrClient().
query(query).getResults();
/**
* The following was commented for the test,
* so that it can be told where the leak comes from.
*
*/
// listOfMyDocumentsAlreadyIndexed = results.parallelStream()
// .map((doc) -> { // different stuff ...
// return myDocument;
// })
// .collect(Collectors.toList());
return listOfMyDocumentsAlreadyIndexed;
/** The number of surviving generations
* keeps increasing whereas if null is
* returned then the number of surviving
* generations is not increasing anymore
*/
}
我从分析器中得到这个(在将近 200 运行s 之后可以为我的程序模拟一年的 运行 时间):
存活最多的对象是String
:
在查询索引中的所有文档时,存活代数的增加是否是预期的行为?
如果是这样的话,这是我在生产服务器上一段时间后遇到的 "OOM Java heap space" 错误的根本原因,因为它似乎来自堆栈跟踪:
Exception in thread "Timer-0" java.lang.OutOfMemoryError: Java heap space
at org.noggit.CharArr.resize(CharArr.java:110)
at org.noggit.CharArr.reserve(CharArr.java:116)
at org.apache.solr.common.util.ByteUtils.UTF8toUTF16(ByteUtils.java:68)
at org.apache.solr.common.util.JavaBinCodec.readStr(JavaBinCodec.java:868)
at org.apache.solr.common.util.JavaBinCodec.readStr(JavaBinCodec.java:857)
at org.apache.solr.common.util.JavaBinCodec.readObject(JavaBinCodec.java:266)
at org.apache.solr.common.util.JavaBinCodec.readVal(JavaBinCodec.java:256)
at org.apache.solr.common.util.JavaBinCodec.readSolrDocument(JavaBinCodec.java:541)
at org.apache.solr.common.util.JavaBinCodec.readObject(JavaBinCodec.java:305)
at org.apache.solr.common.util.JavaBinCodec.readVal(JavaBinCodec.java:256)
at org.apache.solr.common.util.JavaBinCodec.readArray(JavaBinCodec.java:747)
at org.apache.solr.common.util.JavaBinCodec.readObject(JavaBinCodec.java:272)
at org.apache.solr.common.util.JavaBinCodec.readVal(JavaBinCodec.java:256)
at org.apache.solr.common.util.JavaBinCodec.readSolrDocumentList(JavaBinCodec.java:555)
at org.apache.solr.common.util.JavaBinCodec.readObject(JavaBinCodec.java:307)
at org.apache.solr.common.util.JavaBinCodec.readVal(JavaBinCodec.java:256)
at org.apache.solr.common.util.JavaBinCodec.readOrderedMap(JavaBinCodec.java:200)
at org.apache.solr.common.util.JavaBinCodec.readObject(JavaBinCodec.java:274)
at org.apache.solr.common.util.JavaBinCodec.readVal(JavaBinCodec.java:256)
at org.apache.solr.common.util.JavaBinCodec.unmarshal(JavaBinCodec.java:178)
at org.apache.solr.client.solrj.impl.BinaryResponseParser.processResponse(BinaryResponseParser.java:50)
at org.apache.solr.client.solrj.impl.HttpSolrClient.executeMethod(HttpSolrClient.java:614)
at org.apache.solr.client.solrj.impl.HttpSolrClient.request(HttpSolrClient.java:255)
at org.apache.solr.client.solrj.impl.HttpSolrClient.request(HttpSolrClient.java:244)
at org.apache.solr.client.solrj.SolrRequest.process(SolrRequest.java:194)
at org.apache.solr.client.solrj.SolrClient.query(SolrClient.java:942)
at org.apache.solr.client.solrj.SolrClient.query(SolrClient.java:957)
将堆 space ("-Xmx") 从 8GB 增加到任何更大的值肯定会解决问题还是只是推迟它?可以做些什么来解决这个问题?
几个小时后编辑
如果从被测方法返回 null
(getListOfMyDocumentsAlreadyIndexed
) 那么在整个测试过程中幸存世代的数量保持稳定:
所以即使我没有使用这个测试的查询结果(因为我只想关注泄漏发生的地方)它看起来像返回一个实例变量(即使它是空的)不是一个好主意。我会尝试删除它。
稍后编辑
我注意到当我分析 "defined classes" ("focused (instrumented)") 时,遥测选项卡中的幸存世代仍在增加,而分析 "All classes" ("General (sampled)").所以我不确定它是否解决了问题:
非常感谢任何提示:-)
问题源于以下行:
query.setRows(Integer.MAX_VALUE);
根据这篇文章不应该这样做:
The rows parameter for Solr can be used to return more than the default of 10 rows. I have seen users successfully set the rows parameter to 100-200 and not see any issues. However, setting the rows parameter higher has a big memory consequence and should be avoided at all costs.
因此,通过 this solr article on pagination 之后的 200 个文档块检索文档解决了问题:
SolrQuery q = (new SolrQuery(some_query)).setRows(r).setSort(SortClause.asc("id"));
String cursorMark = CursorMarkParams.CURSOR_MARK_START;
boolean done = false;
while (! done) {
q.set(CursorMarkParams.CURSOR_MARK_PARAM, cursorMark);
QueryResponse rsp = solrServer.query(q);
String nextCursorMark = rsp.getNextCursorMark();
doCustomProcessingOfResults(rsp);
if (cursorMark.equals(nextCursorMark)) {
done = true;
}
cursorMark = nextCursorMark;
}
请注意:setRows
中的文档不应超过 200 个,否则内存泄漏仍然会发生(例如,500 个文档确实会发生)。
现在,分析器在存活世代方面给出了更好的结果,因为它们不再随时间增加。
但是该方法要慢得多。