java - 在运行 Solr 查询时,存活的代数不断增加
问题描述
我正在使用 jSolr (7.4) 测试一个查询,因为我相信它会导致我的程序出现内存泄漏。但是我不确定这是否确实是内存泄漏,所以我呼吁建议!
此方法在我的索引程序运行期间被多次调用(应该能够运行数周/数月而不会出现任何问题)。这就是我在使用 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 次运行,可以模拟我的程序一年的运行时间):
最幸存的对象是String
:
在查询索引中的所有文档时,不断增长的存活代数是否是预期的行为?
如果是这样,这是我在生产服务器上一段时间后得到的“OOM Java堆空间”错误的根本原因,因为它似乎来自stacktrace:
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)
将堆空间(“-Xmx”)从 8GB 增加到更大的容量肯定会解决问题还是会推迟它?可以做些什么来解决这个问题?
几个小时后编辑
如果null
从被测方法返回 ( getListOfMyDocumentsAlreadyIndexed
),则在整个测试过程中存活的世代数保持稳定:
因此,即使我没有使用此测试的查询结果(因为我只想关注泄漏发生的位置),看起来返回一个实例变量(即使它为空)也不是一个好主意。我会尝试删除它。
稍后再编辑
我注意到当我分析“定义的类”(“聚焦(仪器)”)时,遥测选项卡中幸存的世代仍在增加,而在分析“所有类”(“常规(采样)”)时它是稳定的。所以我不确定它是否解决了问题:
非常感谢任何提示:-)
解决方案
问题源于以下行:
query.setRows(Integer.MAX_VALUE);
根据这篇文章不应该这样做:
Solr 的 rows 参数可用于返回超过默认值的 10 行。我已经看到用户成功地将 rows 参数设置为 100-200 并且没有看到任何问题。但是,将 rows 参数设置得更高会产生很大的内存后果,应该不惜一切代价避免。
因此,问题已通过按照有关分页的 solr 文章按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;
}
请注意:您不应超过 200 个文档,setRows
否则内存泄漏仍然会发生(例如 500 个确实会发生)。
现在,剖析器对幸存的世代提供了更好的结果,因为它们不再随时间增加。
但是,该方法要慢得多。
推荐阅读
- android - Android:添加 exoplayer 时出现空对象引用错误
- twilio - 如何在 Twilio 中切换视频录制
- android - 在android中使用数据绑定设置滚动标志
- amazon-web-services - AWS 无服务器自定义 jwt 授权方 lambda 设置 cors 响应
- javascript - 我一直在修复此共享短信功能的错误,但是当我通过 google messenger 应用程序共享时,它不会预先填充文本正文
- php - 奇怪的解析错误:语法错误,意外`'if' (T_IF) ERROR`
- php - php合并两个动态数组递归
- angular - 将 [pageSize] 属性添加到 Kendo 网格后的 ExpressionChangedAfterItHasBeenCheckedError
- regex - 使用 Hive / Spark SQL 在 URL 中匹配字符串
- ibm-domino - 如何处理收件人地址中的空间