正如您所注意到的,java.net.http.HttpClient没有实现Closeable或AutoCloseable。所以我只能想到两个选择,但它们都不是真正的防弹甚至是好的: 您可以将每个strong reference消除为程序保存的HttpClient和request a garbage collection。然而,有一个真实的的风险,即超出你直接控制的东西正在抓住它或它的一个组成部分。任何剩余的强引用都将阻止被引用的对象以及它持有强引用的任何对象被垃圾回收。尽管如此,这可以说是比另一种选择更惯用的选择。 我还找到了另一个选择。
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();
}
...
}
除非别无选择,否则我不会使用它。您的引用可能是HttpClient类型,因此需要将其强制转换为HttpClientImpl。依赖于具体的实现是不好的,而不是HttpClient接口,在未来的版本中可能会发生变化。方法也是私有的。有ways around this,但它是混乱的。
7条答案
按热度按时间ecfsfe2w1#
我在将一个war文件重新部署到Tomcat中时遇到了类似的问题。War应用程序有一个HttpClient,它正在运行调度的作业,发出http请求并处理结果。
当在开发环境中重新部署war文件时,我经常看到Tomcat的警告,这些警告可能会导致内存泄漏。堆栈跟踪指向HttpClient线程。经过几次尝试,我用这种方式解决了这个问题:
ExecutorService executor = Executors.newSingleThreadExecutor(); HttpClient client = HttpClient.newBuilder().followRedirects(Redirect.ALWAYS).connectTimeout(Duration.ofSeconds(5)).executor(executor).build();
1.当在try-catch块中完成作业时,finally部分有以下两行:显式关闭线程池,并将httpClient局部变量设置为null:
executor.shutdownNow(); client = null; System.gc();
注意,有一个短的连接超时来限制执行时间。保持线程数量较小。我使用1个线程的threadPool。
在所有这些更改之后,有关内存泄漏的警告从Tomcat日志中消失了。
e4yzc0pl2#
正如您所注意到的,
java.net.http.HttpClient
没有实现Closeable
或AutoCloseable
。所以我只能想到两个选择,但它们都不是真正的防弹甚至是好的:您可以将每个strong reference消除为程序保存的
HttpClient
和request a garbage collection。然而,有一个真实的的风险,即超出你直接控制的东西正在抓住它或它的一个组成部分。任何剩余的强引用都将阻止被引用的对象以及它持有强引用的任何对象被垃圾回收。尽管如此,这可以说是比另一种选择更惯用的选择。我还找到了另一个选择。
除非别无选择,否则我不会使用它。您的引用可能是
HttpClient
类型,因此需要将其强制转换为HttpClientImpl
。依赖于具体的实现是不好的,而不是HttpClient
接口,在未来的版本中可能会发生变化。方法也是私有的。有ways around this,但它是混乱的。mbzjlibv3#
在Java 11中,每个
HttpClient
都会产生一个名为selmgr
的守护进程线程,该线程应该负责处理飞行请求。当代码中没有对HttpClient
的引用时,此线程将关闭。但是,根据我的经验,这是不可靠的。特别是在使用具有未来超时的异步方法时。下面是我使用反射编写的一段代码,它可靠地关闭了
HttpClient
正如您所看到的,这是依赖于实现的,可能不适用于未来的Java版本。在Java 11和Java 12中测试。
另外,您需要将
--add-opens java.net.http/jdk.internal.net.http=ALL-UNNAMED
添加到Java命令中。4urapxun4#
显然,
HttpClient
被设计为自我管理。所以它负责维护连接池,自己缓存ttl。在
HttpClientCode
中,我们可以找到以下代码:这是退出
SelectorManager
循环并清除所有资源的优雅方式。因此,当您的
HttpClient
对象不会被引用时,它将清理所有资源。UPD:你还应该通过传递超时来调优你的请求
ee7vknir5#
这有点晚了,但我只想强调一下Jacob G.(2018年12月25日)包含了一个对我有效的解决方案:
创建httpclient:
关闭:
而不是必须等待90秒的客户端放弃其连接,它发生“瞬间”。
7fhtutme6#
如果只是为了在应用程序生命周期结束时优雅地关闭HttpClient,System.exit(0)就可以了。
我认为它会向JVM中的所有线程发送中断信号,HttpClient selmgr守护进程会接收到这个信号并自行关闭。
46qrfjad7#
根据Java 21,
HttpClient
实现了AutoCloseable
。它还获得了方法shutdown()
、shutdownNow()
和awaitTermination()
,它们的工作方式与ExecutorService
上的同名方法类似。shutdownNow()
应该能满足你的需求。