关闭 Java HTTP Client

2022-09-01 21:19:52

有没有办法关闭,立即释放它所持有的资源?java.net.http.HttpClient

在内部,它包含一个选择器,一个连接池和一个(当使用默认连接池时)。但是,它不实现 /。ExecutorCloseableAutoCloseable


答案 1

当我将战争文件重新部署到Tomcat时,我遇到了类似的问题。War 应用程序有一个 HttpClient,它运行调度作业,发出 http 请求并处理结果。

在开发时,我经常在开发时看到Tomcat的警告,这些警告涉及可能导致内存泄漏的挂起线程。堆栈跟踪指向 HttpClient 线程。经过几次尝试,我以这种方式解决了这个问题:

  1. 仅当需要执行作业时,才会创建 HttpClient。它不是作为类或 serivec 的字段创建的,而只是作为调度方法中的局部变量创建。

  2. HttpClient是使用builder创建的,并填充了ThreadPool Executor,因此我保留了指向Executor的链接并对其进行了控制。 ExecutorService executor = Executors.newSingleThreadExecutor(); HttpClient client = HttpClient.newBuilder().followRedirects(Redirect.ALWAYS).connectTimeout(Duration.ofSeconds(5)).executor(executor).build();

  3. 当在 try-catch 块中完成工作时,最后部分有以下两行:显式关闭线程池并将 null 设置为 httpClient 局部变量: executor.shutdownNow(); client = null; System.gc();

注意,具有较短的连接超时以限制执行时间。保持较小的线程数。我使用1个线程的线程池。

在所有这些更改之后,有关内存泄漏的警告从Tomcat日志中消失了。


答案 2

如您所见,不实现 或 。所以我只能想到2个选项,但它们都不是真正的防弹甚至好:java.net.http.HttpClientCloseableAutoCloseable

您可以消除对程序所持有的每个强引用,并请求垃圾回收。但是,存在一个真正的风险,即超出您直接控制范围的东西正在抓住它或其组件之一。任何剩余的强引用都会阻止被引用的对象及其持有强引用的任何对象被垃圾回收。然而,这可以说是比替代方案更惯用的选择。HttpClient

我还找到了另一种选择

final class HttpClientImpl extends HttpClient implements Trackable {
    ...
    // Called from the SelectorManager thread, just before exiting.
    // Clears the HTTP/1.1 and HTTP/2 cache, ensuring that the connections
    // that may be still lingering there are properly closed (and their
    // possibly still opened SocketChannel released).
    private void stop() {
        // Clears HTTP/1.1 cache and close its connections
        connections.stop();
        // Clears HTTP/2 cache and close its connections.
        client2.stop();
    }
    ...
}

除非我别无选择,否则我不会放心使用它。您的引用可能是 类型 ,因此您需要将其转换为 。依赖具体的实现是不好的,它在未来的版本中可能会改变,而不是接口。该方法也是私有的。有办法解决这个问题,但它很混乱。HttpClientHttpClientImplHttpClient


推荐