Tomcat 和垃圾收集数据库连接
Tomcat and garbage collecting database connections
我前两天问过(然后自己回答),解决了问题,但是我不太明白为什么问题解决了并希望得到一些澄清。
本质上,我已经实现了一个基于 jax-rs 的 REST 服务,该服务从 RavenDB 数据库中检索信息并 returns 流中的内容。我遇到的问题是一个未关闭的数据库结果迭代器,它导致 REST 服务在恰好 10 个请求后挂起(并且不再接受进一步的请求)。
我的代码大致如下:
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,它也应该退出 scope/become 在我的方法以 400 或 200 状态结束时无法访问 - 因此得到垃圾收集。
明确一点:我当然不是建议人们不应该正确关闭打开的连接等 - 我现在正在这样做 - 或者依靠 Java 的垃圾收集机制来拯救我们lazy/unclean 编码......我只是在努力理解那些未关闭的迭代器是如何导致观察到的 Tomcat 行为的。
事实上,我的假设是我们甚至不需要知道有关迭代器实现的细节,因为在 Java 对象生命周期的 "galactic level" 处,实现差异是无关紧要的。 => "Once an object has become unreachable, it doesn't matter exactly how it was coded"。
我唯一能想到的是 Tomcat 以某种方式(通过它的容器机制?),稍微改变了这里的游戏,并导致事情变成 "hang around"。
有人可以解释一下吗?
提前致谢!
CloseableIterator
指的是 CloseableHttpResponse
,后者指的是 HTTP 连接。当 CloseableIterator
不再可达时,终结器不会释放响应或连接。您造成了连接泄漏。您的错误类似于此处描述的错误:https://phillbarber.blogspot.com/2014/02/lessons-learned-from-connection-leak-in.html
在这里查看为什么释放资源的终结方法不是一个好主意:https://www.baeldung.com/java-finalize
我前两天问过(然后自己回答)
本质上,我已经实现了一个基于 jax-rs 的 REST 服务,该服务从 RavenDB 数据库中检索信息并 returns 流中的内容。我遇到的问题是一个未关闭的数据库结果迭代器,它导致 REST 服务在恰好 10 个请求后挂起(并且不再接受进一步的请求)。
我的代码大致如下:
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,它也应该退出 scope/become 在我的方法以 400 或 200 状态结束时无法访问 - 因此得到垃圾收集。
明确一点:我当然不是建议人们不应该正确关闭打开的连接等 - 我现在正在这样做 - 或者依靠 Java 的垃圾收集机制来拯救我们lazy/unclean 编码......我只是在努力理解那些未关闭的迭代器是如何导致观察到的 Tomcat 行为的。
事实上,我的假设是我们甚至不需要知道有关迭代器实现的细节,因为在 Java 对象生命周期的 "galactic level" 处,实现差异是无关紧要的。 => "Once an object has become unreachable, it doesn't matter exactly how it was coded"。 我唯一能想到的是 Tomcat 以某种方式(通过它的容器机制?),稍微改变了这里的游戏,并导致事情变成 "hang around"。 有人可以解释一下吗?
提前致谢!
CloseableIterator
指的是 CloseableHttpResponse
,后者指的是 HTTP 连接。当 CloseableIterator
不再可达时,终结器不会释放响应或连接。您造成了连接泄漏。您的错误类似于此处描述的错误:https://phillbarber.blogspot.com/2014/02/lessons-learned-from-connection-leak-in.html
在这里查看为什么释放资源的终结方法不是一个好主意:https://www.baeldung.com/java-finalize