HttpClient的释放资源到底在释放什么?如何正确的释放资源?

ApacheHttpClient github地址:https://github.com/apache/httpcomponents-client/tree/4.5.x

ApacheHttpClient官网地址:https://hc.apache.org/httpcomponents-client-4.5.x/index.html

ApacheHttpClient介绍

本文主要想聊一聊ApacheHttpClient中资源释放的那些事,如果对它不够了解的话可以参考下面的思维导图:

链接:https://www.processon.com/view/link/641ef425fc0140496f0a3961

ApacheHttpClient

资源类型分类

在聊这个话题前我们先要明确HttpClient中定义的资源是什么,在HttpClient中需要释放的资源可以分为四种

  1. 内存,应用层用于发送请求或接收响应

  2. 底层Sokcet

  3. Http连接,一个Http连接对应了一块用于收发数据的内存,同时绑定了一个socket。如下所示:

    image-20230326003928005

  4. Http连接池

收发数据的内存跟socket是绑定在连接对象上的,所以如果我们正常关闭了连接,那么也就完成了对这两种资源的释放

Http连接池通常我们不会关闭,如果关闭了Http连接池意味着整个HttpClient对象不能再被使用

资源释放API介绍

我们常用的资源释放的API可以分为下面几类

  1. HttpRequestBase对象的releaseConnectionabort方法,HttpGet、HttpPost都继承了这个类。

    源码如下:

    abort

    release

    这两个方法最终都会调用cancellableRef引用的对象的cancel方法,cancellableRef在不同的时机对应不同的资源对象:ConnectionRequest,代表一个从连接池中获取连接的请求。ConnectionHolder,代表一个真实的http连接

    代码位于:org.apache.http.impl.execchain.MainClientExec#execute

    image-20230325235403131

    当调用ConnectionRequest的cancel方法时,代表取消本次获取连接的请求。当调用ConnectionHolder的cancel方法时,代表什么呢?代码如下:org.apache.http.impl.execchain.ConnectionHolder#abortConnection

    image-20230326000714850

    上面代码主要做了两件事:关闭socket连接,归还连接到连接池。可能有的小伙伴会有疑问,为什么把连接绑定的socket关闭了还要将连接归还到连接池呢?这是因为连接池中的连接数量是有限制的,假设我们设置设置了最大连接数为10,如果不把这个连接归还到连接池,那么它会一直占用一个连接名额直到被驱逐策略所驱逐。并且在调用连接池的releaseConnection方法时,会判断归还的连接是否可用,如果不可用会直接从连接池中移除这个对象

    代码:org.apache.http.impl.conn.PoolingHttpClientConnectionManager#releaseConnection

    image-20230326001731861

  2. CloseableHttpResponse对象的close方法

    最终会调用org.apache.http.impl.conn.PoolingHttpClientConnectionManager#releaseConnection

    image-20230326003013159

    可以看到,当调用response对象的close方法,会关闭socket,同时释放连接到连接池。这里顺便说一下,连接的close方法跟shutdown方法的区别在于,close方法会尝试将未写完的数据全部写入server端,而shutdown会直接丢弃

  3. EntityUtils的consume方法跟toString方法以及关闭HttpEntity中的流

    EntityUtils的consume、toString最终都是调用HttpEntity.getContent().close方法,实际都是在关闭HttpEntity中的流

    最终会调用:org.apache.http.impl.execchain.ResponseEntityProxy#streamClosed

    image-20230326005604357

    wrapped.close()最终会调用org.apache.http.impl.io.ContentLengthInputStream#close,代码如下:image-20230326005915733

    可以看到,它只是简单的读取数据但没有进行其它任何操作,这实际是为了释放我们在前文提到了内存。这是为了安全的复用连接,我们需要将上次请求接收并缓存的所有数据清理干净,否则下次使用这个连接时可能读取到上次请求没有读取完的数据

  4. CloseableHttpClient对象的close方法

    这个方法会关闭所有HttpClient对象涉及的资源,包括连接池,HttpClient对象建议全局共享一个,因此一般不会调用

正确的释放资源

通过上面的分析,正确的资源释放姿势如下:

private static final CloseableHttpClient httpclient = HttpClients.createDefault();
public static void main(String[] args) throws Exception {
  try {
    HttpGet httpGet = new HttpGet("http://httpbin.org/get");
    CloseableHttpResponse response = httpclient.execute(httpGet);
    try {
      HttpEntity entity1 = response.getEntity();

      // 确保内存完成释放
      final String json = EntityUtils.toString(entity1);
      // 完成业务处理....
      
    }catch(){
      // 异常处理....
    } 
    finally {
      // 保证连接释放,如果EntityUtils.toString调用成功,这个方法实际上不会做任何操作
      response.close();
    }
  }
  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
HttpClient close_wait不释放是指当HttpClient执行完请求后,关闭连接后却不能及时释放连接,出现了close_wait状态,可能会导致资源的浪费和程序性能的降低。这种情况通常发现在服务器的TCP连接数一直在增加,却一直处于close_wait状态,并且ClientSocketImpl的状态一直是CLOSED_WAIT,造成资源的浪费和服务器处理能力的下降。 造成HttpClient close_wait不释放的原因可能有以下几点: 1. 连接池没有及时释放连接。HttpClient有一个默认的连接池管理器,如果连接池同时被多个线程调用,可能会出现连接池没有及时释放连接的情况,导致close_wait状态的产生。 2. Http客户端没有及时关闭连接。有些Http客户端请求完成后不主动释放连接,导致连接一直处于close_wait状态。 3. 服务器没有及时关闭连接。如果服务器没有在超时时间内关闭连接,那么连接就会一直处于close_wait状态。 解决HttpClient close_wait不释放的方法有以下几点: 1. 使用HttpClient连接池管理器时,需要设置合理的连接超时时间和请求超时时间,及时关闭闲置连接或者过期的连接。 2. 在Http客户端请求完成后,及时关闭连接,避免连接一直处于close_wait状态。 3. 调整服务器的超时时间,及时关闭连接。 4. 调整服务器的TCP/IP协议参数,设置合理的TIME_WAIT时间。 总之,为了避免出现close_wait状态的连接,需要在使用HttpClient连接池管理器时,合理调整连接超时时间和请求超时时间,并在请求完成后及时释放连接,避免资源的浪费和程序性能的降低。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值