关闭Java HTTP客户端

Vla*_*ich 9 java java-http-client java-11

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

在内部,它包含一个选择器,一个连接池和一个Executor(当使用默认值时).但它没有实现Closeable/ AutoCloseable.

kac*_*nov 5

我在将 war 文件重新部署到 Tomcat 时遇到了类似的问题。War 应用程序有一个 HttpClient,它运行预定作业,发出 http 请求和处理结果。

在开发环境中经常重新部署 war 文件时,我经常看到来自 Tomcat 的警告,关于挂起的线程可能会导致内存泄漏。堆栈跟踪指向 HttpClient 线程。经过多次尝试,我以这种方式解决了这个问题:

  1. HttpClient 仅在需要执行作业时创建。它不是作为类或服务的字段创建的,而是作为调度方法内的局部变量创建的。

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

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

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

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


Flo*_*oky 3

正如您所注意到的,java.net.http.HttpClient没有实现Closeableor AutoCloseable。所以我只能想到两个选择,但它们都不是真正万无一失的,甚至都不是好的:

您可以消除对程序所持有的所有强引用并请求垃圾收集。然而,存在一个真正的风险,即超出您直接控制范围的东西正在保留它或其组件之一。任何剩余的强引用都会阻止被引用的对象及其持有强引用的任何对象被垃圾收集。尽管如此,这可以说是比其他选择更惯用的选择。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();
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

除非我别无选择,否则我不会觉得使用这个很舒服。您的引用可能属于 类型HttpClient,因此您需要将其转换为HttpClientImpl. 依赖具体的实现而不是接口是不好的,具体的HttpClient实现可能在未来的版本中发生变化。该方法也是私有的。有很多方法可以解决这个问题,但很混乱。