2013-05-22 36 views
1

我有以下代碼(安卓4.0):HttpURLConnection類不免費資源

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()時,保活設置爲false和最大連接數設置爲5。但是,如果出現SocketTimeoutexception ,連接不會關閉,設備很快就會出現內存不足的情況。這怎麼可能?

另外,根據http://developer.android.com/reference/java/net/HttpURLConnection.htmlHttpURLConnectiondisconnect()關閉連接,如果保活設置爲false和重用它時,保活是true。這些方法都不適用於我。任何想法可能是錯的?

回答

0

一種可能性是您沒有儘快設置屬性。根據javadoc,在發出任何HTTP請求之前,「Keepalive」屬性需要設置爲假之前。這可能是實際上意味着URL協議驅動程序初始化之前。

另一種可能性是您的OOME根本不是由此造成的。這可能是由您的應用對其下載的內容所做的。


您的代碼還存在其他一些問題。

  • 變量名url_service_bufferedReadermyurl都侵犯了Java的標識符命名約定。

  • conn變量應該是局部變量。使其成爲字段使downloadUrl方法不可重入。 (這可能有助於你的問題......如果多個線程共享這個對象的一個​​實例!)

  • 你並不需要關閉緩存讀取器和輸入流。關閉閱讀器,它會關閉流。這對讀者來說可能並不重要,但是如果你爲緩衝作家做了這些工作,並且首先關閉了輸出流,那麼你可能會遇到異常。


UPDATE

所以我們肯定有很多非垃圾HttpURLConnectionImpl實例,我們可能不得不通過AsyncTask運行此代碼的多個線程。

如果您嘗試連接到一個無響應的站點(例如,其中TCP/IP連接請求黑洞......),那麼conn.connect()呼叫將會阻塞很長時間,並最終引發異常。如果連接超時時間足夠長,並且您的代碼並行執行了這些調用的潛在無限數量,那麼您可能會擁有大量這些實例。

如果這個理論是正確的,那麼你的問題與保持聯繫和連接沒有關閉沒有關係。問題在於另一端......連接永遠無法正確建立,首先會堵塞內存,並且每個連接都佔用一個線程/線程堆棧:

  • 嘗試減少連接超時。
  • 嘗試運行使用Executor有界線程池這些請求。

注意它在AsyncTask javadoc中說:

「的AsyncTask的設計是圍繞線程和處理程序一個輔助類,並不構成通用線程框架AsyncTasks最好應使用。短期操作(最多幾秒鐘)。如果你需要保持對長時間運行的線程,強烈建議您使用介紹java.util.concurrent pacakge如執行人,ThreadPoolExecutor的和FutureTask提供的各種API。 「

+0

我: - 移動「康恩」的方法 內聲明 - - 在方法 的開始搬家「http.keepalive」和「http.maxConnections」命令刪除「is.close()」命令 但是,問題依然存在。 你有什麼想法可能是錯了嗎?有趣的是,只有當連接到服務器失敗時纔會出現問題(超時)。 –

+0

1)你有沒有明確的證據,這個問題是漏水的HTTP連接?或者這只是一個理論? 2)你是否在第2號子彈中考慮過這個問題?您的應用是否使用多個線程進行下載? –

+0

廣告1)是的。 MAT for Eclipse顯示:由「<系統類加載器>」加載的「libcore.net.http.HttpURLConnectionImpl」的568個實例佔用1.448.712(15,07%)個字節。 廣告2)是,我「運動參數conn」變量** **內的方法,但問題仍然存在。 廣告3)應用程序使用的AsyncTask用於此目的,所以它是** **可能有被同時執行,該方法的多個實例。 –