几天前,我问(并回答了自己)this question,并解决了问题,但我不太明白为什么为什么并希望得到解决一些澄清。
从本质上讲,我已经实现了基于jax-rs的REST服务,该服务从RavenDB数据库中检索信息并以流的形式返回该内容。我遇到的问题是一个未关闭的数据库结果迭代器,导致恰好10个请求后REST服务挂起(并且不接受其他任何请求)。
我的代码大致如下:
public Response ...
{
(...)
StreamingOutput adminAreaStream = new StreamingOutput()
{
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
@Override
public void write(OutputStream output) throws IOException, WebApplicationException
{
try(IDocumentSession currentSession = ServiceListener.ravenDBStore.openSession())
{
Writer writer = new BufferedWriter(new OutputStreamWriter(output));
(...)
CloseableIterator<StreamResult<AdministrativeArea>> results;
(...)
writer.flush();
writer.close();
results.close();
currentSession.advanced().clear();
currentSession.close();
}
catch (Exception e)
{
System.out.println("Exception: " + e.getMessage() + e.getStackTrace());
}
}
};
if(!requestIsValid)
return Response.status(400).build();
else
return Response.ok(adminAreaStream).build();
}
根据我对Java对象生命周期的了解,或更确切地说,是对象可访问性和垃圾回收,即使我没有正确关闭CleasableIterator,它也应该超出范围/在我的方法完成时变得无法访问状态为400或200-因此会收集垃圾。
请明确一点:我当然不是在建议不要适当地关闭打开的连接等。-我现在正在这样做-或依靠Java的垃圾收集机制来使我们免于懒惰/不干净的编码...我我只是在努力确切地了解那些未封闭的迭代器是如何导致观察到的Tomcat行为的。
实际上,我的假设是我们甚至不需要了解有关迭代器实现的详细信息,因为在Java的“银河级”对象生命周期中,实现差异是无关紧要的。 =>“一旦对象变得不可访问,则它的编码方式无关紧要”。 我只能想象的是,Tomcat以某种方式(通过其容器机制?)稍微改变了这里的游戏,并导致事情“四处徘徊”。 有人可以对此有所说明吗?
谢谢!
答案 0 :(得分:2)
CloseableIterator
指的是CloseableHttpResponse
,指的是HTTP连接。当CloseableIterator
不再可访问时,没有终结器会释放响应或连接。您创建了连接泄漏。您的错误类似于此处描述的错误:https://phillbarber.blogspot.com/2014/02/lessons-learned-from-connection-leak-in.html
请参见此处,为什么用finalize方法释放资源是一个坏主意:https://www.baeldung.com/java-finalize