【问题标题】:HttpURLConnection does not free resourcesHttpURLConnection 不释放资源
【发布时间】:2013-05-22 09:41:47
【问题描述】:

我有以下代码(Android 4):

private HttpURLConnection conn = null;

private synchronized String downloadUrl(String myurl) {
    InputStream is = null;
    BufferedReader _bufferReader = null;
    try {
        URL url_service = new URL(.....);
        System.setProperty("http.keepAlive", "false");
        System.setProperty("http.maxConnections", "5");
        conn = (HttpURLConnection) url_service.openConnection();
        conn.setReadTimeout(DataHandler.TIME_OUT);
        conn.setConnectTimeout(DataHandler.TIME_OUT);
        conn.setRequestMethod("POST");
        conn.setDoInput(true);
        conn.setDoOutput(true);
        conn.setRequestProperty("connection", "close");
        conn.setInstanceFollowRedirects(false);
        conn.connect();
        StringBuilder total = null;
        if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
            is = conn.getInputStream();
            _bufferReader = new BufferedReader(new InputStreamReader(is));
            total = new StringBuilder();
            String line;
            while ((line = _bufferReader.readLine()) != null) {
                total.append(line);
            }

        } else {
            onDomainError();
        }

        return total.toString();

    } catch (SocketTimeoutException ste) {
        onDomainError();
    } catch (Exception e) {
        onDomainError();

    } finally {
        if (is != null) {
            try {
                is.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block

            }

        }
        if (_bufferReader != null) {
            try {
                _bufferReader.close();
            } catch (Exception e) {
                // TODO: handle exception
            }
        }

        if (conn != null)
            conn.disconnect();
        conn = null;

    }
    return null;
}

使用.disconnect(),keep-alive 设置为false,最大连接数设置为5。但是,如果出现SocketTimeout exception,连接不会关闭,设备很快就会内存不足。这怎么可能?

另外,根据http://developer.android.com/reference/java/net/HttpURLConnection.html,如果keep-alive 设置为falseHttpURLConnection 应该关闭disconnect() 上的连接,并在keep-alive 为true 时重用它。这些方法都不适合我。有什么想法可能是错的吗?

【问题讨论】:

    标签: java android httpconnection


    【解决方案1】:

    一种可能性是您没有足够快地设置属性。根据 javadoc,“keepalive”属性需要在发出任何 HTTP 请求之前设置为 false。这可能实际上意味着在 URL 协议驱动程序初始化之前。

    另一种可能是您的OOME根本不是由此引起的。这可能是由于您的应用对已下载内容的处理方式造成的。


    您的代码也存在一些其他问题。

    • 变量名url_service_bufferedReadermyurl都违反了Java的标识符命名约定。

    • conn 变量应该是一个局部变量。将其设为字段会使downloadUrl 方法不可重入。 (并且可能会导致您的问题......如果多个线程共享此对象的一个​​实例!)

    • 您无需关闭缓冲读取器和输入流。只需关闭阅读器,它就会关闭流。这对读者来说可能无关紧要,但如果你为缓冲的写者这样做并且你先关闭输出流,你很可能会遇到异常。


    更新

    所以我们肯定有很多非垃圾 HttpURLConnectionImpl 实例,而且我们可能有多个线程通过 AsyncTask 运行此代码。

    如果您尝试连接到无响应的站点(例如 TCP/IP 连接请求是黑洞的站点...),那么 conn.connect() 调用将阻塞很长时间并最终抛出例外。如果连接超时时间足够长,并且您的代码正在并行执行可能无限数量的这些调用,那么您很可能会有很多这样的实例。

    如果这个理论是正确的,那么你的问题与保持活动和连接没有被关闭无关。问题出在另一端……一开始就没有正确建立的连接堵塞了内存,并且每个连接都占用了一个线程/线程堆栈:

    • 尝试减少连接超时。
    • 尝试使用带有有限线程池的Executor 运行这些请求。

    注意AsyncTask javadoc 中的内容:

    “AsyncTask 被设计成一个围绕 Thread 和 Handler 的辅助类,并不构成一个通用的线程框架。AsyncTasks 应该理想地用于短操作(最多几秒钟)。如果你需要保持线程长时间运行,强烈建议您使用 java.util.concurrent 包提供的各种 API,例如 Executor、ThreadPoolExecutor 和 FutureTask。"

    【讨论】:

    • 我做了: - 在方法的开头移动 'http.keepalive' 和 'http.maxConnections' 命令 - 在方法内移动 'conn' 声明 - 删除 'is.close()' 命令但是,问题仍然存在。你知道有什么问题吗?有趣的是,只有在连接到服务器失败(超时)时才会出现问题。
    • 1) 您是否有明确的证据表明问题是 HTTP 连接泄漏?或者这只是一个理论? 2) 您是否考虑过项目符号 #2 中的问题?您的应用是否使用多个线程进行下载?
    • 广告 1) 是的。 Eclipse 的 MAT 显示:“libcore.net.http.HttpURLConnectionImpl”的 568 个实例,由“”加载,占用 1.448.712 (15,07%) 个字节。广告 2) 是的,我将 'conn' 变量 移到了方法内部,但问题仍然存在。广告 3) 应用为此目的使用 AsyncTask,因此可能有多个该方法的实例同时执行。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-09
    • 2012-01-08
    • 2012-05-04
    • 2012-07-27
    • 2018-11-08
    • 1970-01-01
    相关资源
    最近更新 更多