【问题标题】:Tomcat and garbage collecting database connectionsTomcat 和垃圾收集数据库连接
【发布时间】:2018-11-28 21:38:21
【问题描述】:

几天前我问(并回答了自己)this question 并解决了问题,但我不太明白为什么问题已解决,并希望得到一些澄清.

基本上,我已经实现了一个基于 jax-rs 的 REST 服务,该服务从 RavenDB 数据库中检索信息并以流的形式返回该内容。我遇到的问题是一个未关闭的数据库结果迭代器,这导致 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,它应该在我的方法完成时超出范围/变得不可访问状态为 400 或 200 - 因此收集垃圾。

要明确一点:我当然不是建议不应该正确关闭打开的连接等 - 我现在正在这样做 - 或者依靠 Java 的垃圾收集机制来拯救我们免于懒惰/不干净的编码......我我只是在努力理解那些未关闭的迭代器是如何导致观察到的 Tomcat 行为的。

事实上,我的假设是我们甚至不需要知道迭代器实现的细节,因为在 Java 的“银河级”对象生命周期中,实现差异是无关紧要的。 => “一旦一个对象变得无法访问,它的编码方式就无关紧要了”。 我唯一能想象的是,Tomcat 以某种方式(通过其容器机制?)稍微改变了这里的游戏,并导致事情“徘徊”。 有人可以解释一下吗?

提前致谢!

【问题讨论】:

    标签: java tomcat garbage-collection jax-rs database-connection


    【解决方案1】:

    CloseableIterator 指的是 CloseableHttpResponse,它指的是 HTTP 连接。当CloseableIterator 不再可访问时,没有终结器释放响应或连接。您创建了连接泄漏。您的错误与此处描述的错误相似:https://phillbarber.blogspot.com/2014/02/lessons-learned-from-connection-leak-in.html

    在这里了解为什么 finalize 方法释放资源是一个坏主意:https://www.baeldung.com/java-finalize

    【讨论】:

    • 谢谢 - 这正是正在发生的事情......所以公平地说,在我的场景中,归结为我的 http 连接在 Tomcat 中已用尽?这很奇怪,因为数字 10 看起来“非常人性化” - 在我的 server.xml 中,我找不到 10 的明确限制(既不是 maxConnections,也不是 maxThreads)!如果没有特别说明,是否暗示?
    • 看这里:github.com/ravendb/ravendb-jvm-client/blob/v4.1.2/src/main/java/… HttpClientBuilder httpClientBuilder = HttpClients.custom().setMaxConnPerRoute(10); 它被硬编码到 RavenDB 客户端中。您可以通过设置RequestExecutor.configureHttpClient 来更改该值。 IMO 这不是一个非常干净的解决方案......
    • RavenDB Java 客户端库管理其自己的 HTTP 连接(通过 Apache HttpComponents 库)并使用独立于您可以在 Tomcat 中配置的任何内容的内部连接池。
    • @chromanoid 完美答案 - 非常感谢!我有一种预感,这是 Tomcat 无法控制的……
    猜你喜欢
    • 1970-01-01
    • 2015-05-10
    • 1970-01-01
    • 1970-01-01
    • 2012-03-21
    • 2013-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多