• HttpClient的释放问题


    最近遇到了这样一个问题,在Android开启StrictMode的时候,会抛出一个异常如下:

    04-01 16:07:56.864: E/StrictMode(26867): A resource was acquired at attached stack trace but never released. See java.io.Closeable for information on avoiding resource leaks. 
    04-01 16:07:56.864: E/StrictMode(26867): java.lang.Throwable: Explicit termination method 'close' not called
    04-01 16:07:56.864: E/StrictMode(26867):         at dalvik.system.CloseGuard.open(CloseGuard.java:184) 
    04-01 16:07:56.864: E/StrictMode(26867):         at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:271) 
    04-01 16:07:56.864: E/StrictMode(26867):         at com.android.org.conscrypt.OpenSSLSocketImpl.waitForHandshake(OpenSSLSocketImpl.java:598) 
    04-01 16:07:56.864: E/StrictMode(26867):         at com.android.org.conscrypt.OpenSSLSocketImpl.getInputStream(OpenSSLSocketImpl.java:560) 
    04-01 16:07:56.864: E/StrictMode(26867):         at org.apache.http.impl.io.SocketInputBuffer.(SocketInputBuffer.java:70) 
    04-01 16:07:56.864: E/StrictMode(26867):         at org.apache.http.impl.SocketHttpClientConnection.createSessionInputBuffer(SocketHttpClientConnection.java:83) 
    04-01 16:07:56.864: E/StrictMode(26867):         at org.apache.http.impl.conn.DefaultClientConnection.createSessionInputBuffer(DefaultClientConnection.java:170) 
    04-01 16:07:56.864: E/StrictMode(26867):         at org.apache.http.impl.SocketHttpClientConnection.bind(SocketHttpClientConnection.java:106) 
    04-01 16:07:56.864: E/StrictMode(26867):         at org.apache.http.impl.conn.DefaultClientConnection.openCompleted(DefaultClientConnection.java:129) 
    04-01 16:07:56.864: E/StrictMode(26867):         at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:172) 
    04-01 16:07:56.864: E/StrictMode(26867):         at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164) 
    04-01 16:07:56.864: E/StrictMode(26867):         at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119) 
    04-01 16:07:56.864: E/StrictMode(26867):         at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:360) 
    04-01 16:07:56.864: E/StrictMode(26867):         at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555) 
    04-01 16:07:56.864: E/StrictMode(26867):         at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487) 
    04-01 16:07:56.864: E/StrictMode(26867):         at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)
     
    异常大概是说资源没有释放,需要显示的调用close方法。从log上看是网络访问时出现的问题(我使用的是HttpClient)。
    但是在关闭StrictMode的时候程序可以完全正常的运行。原因何在呢?
     
    通过查看HttpClient官方文档发现,在HttpClient请求结束后需要销毁HttpEntity,这样才可以使网络连接返回连接池等待下一次重用(如果不需要重用的话也可以直接关掉连接)。
    官方推荐的HttpEntity销毁方法:HttpEntity#consumeContent
     
    在查看代码时发现,HttpEntity并没有销毁。可是其他网络请求部分的HttpEntity也都没有销毁,为什么只有这一个网络请求会报错呢?而且代码中有监听网络超时并关掉连接的处理,为什么还会出现这个问题呢?
    仔细查看发现,出现问题的部分与其他部分稍有不同。出现问题的网络请求在解析响应的时候,并不需要解析Entity,他的响应结果是放在Headers里面的。也就是说这部分代码在请求结束的时候没有调用HttpResponse#getEntity#getContent方法。
    查看HttpClient文档发现getContent方法也可以使Entity销毁。
    所以就是这个原因使StrictMode抛出资源未释放的异常。
    因为有了网络超时监听的处理,所以在关闭StrictMode的时候并不会出现什么问题,因为没有释放的连接会等到网络超时的时候会被释放。
    在使用HttpClient时一定要注意资源的释放。即使有网络超时自动关闭连接的监听,StrictMode也会报告没有释放资源的异常,因为连接不会立即释放,需要等待超时时间的到来才会release,这样影响了程序的性能。
     
    附HttpClient源码分析:
    1.BasicHttpEntity#getContent源码:
    在getContent方法中将contentObtained置为true;标记content已经被获取过了,在其他地方检测这个标记,如果资源被获取过,那么就会release掉这个连接。
     
    2.BasicHttpEntity#consumeContent源码:
    关闭content(content类型为InputStream)
     
    3.EntityUtils#toString
    在EntityUtils#toString方法的最后直接进行了reader.close();因此直接调用EntityUtils#toString方法后相当于调用了HttpEntity#consumeContent方法
  • 相关阅读:
    【转】使用setuptools简化Python模块的安装
    【转】CPU位数、核数、个数
    JS中的一些注意事项
    关于新浪微博在.net中的应用,配置极其使用
    [字符集]Unicode和UTF8之间的转换详解
    Const用法小结
    C++中虚析构函数的作用
    CTreeCtrl 的一点基础代码
    C2143: 语法错误 C4430: 缺少类型说明符 假定为 int 原因是没有包含头文件(含糊不清,以备查)
    mfc 窗口 分割
  • 原文地址:https://www.cnblogs.com/younghome/p/4609022.html
Copyright © 2020-2023  润新知