在 运行 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 个文档确实会发生)。

现在,分析器在存活世代方面给出了更好的结果,因为它们不再随时间增加。

但是该方法要慢得多。