1

次のコードがあります(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 が に設定されている場合はHttpURLConnection接続を閉じ、keep-alive が の場合は再利用する必要があります。これらのアプローチはどちらも私にはうまくいきません。何が間違っている可能性がありますか?disconnect()falsetrue

4

1 に答える 1

0

1 つの可能性は、プロパティをすぐに設定していないことです。javadoc によると、HTTP リクエストを発行する前に「keepalive」プロパティを false に設定する必要があります。これは実際には、URL プロトコル ドライバーが初期化される前を意味する場合があります。

別の可能性として、これが原因で OOME がまったく発生していない可能性があります。ダウンロードしたコンテンツに対するアプリの処理が原因である可能性があります。


コードには他にもいくつかの問題があります。

  • 変数名url_service_bufferedReaderおよびmyurlはすべて、Java の識別子の命名規則に違反しています。

  • conn変数はローカル変数である必要があります。これをフィールドにすると、downloadUrlメソッドは再入不可になります。(そして、それが問題の原因になっている可能性があります...複数のスレッドがこのオブジェクトの 1 つのインスタンスを共有している場合!)

  • バッファリングされたリーダーと入力ストリームを閉じる必要はありません。リーダーを閉じるだけで、ストリームが閉じます。これはおそらくリーダーにとっては問題ではありませんが、バッファリングされたライターに対してそれを行い、最初に出力ストリームを閉じると、例外が発生する可能性があります。


アップデート

したがって、ガベージではないHttpURLConnectionImplインスタンスが多数存在することは間違いありません。おそらく、複数のスレッドが を介してこのコードを実行していますAsyncTask

応答しないサイト (TCP/IP 接続要求がブラックホールになっているサイトなど) に接続しようとすると、conn.connect()呼び出しが長時間ブロックされ、最終的に例外がスローされます。接続タイムアウトが十分に長く、コードが潜在的に無制限の数のこれらの呼び出しを並行して実行している場合、これらのインスタンスが多数発生する可能性があります。

この理論が正しい場合、問題はキープアライブと接続が閉じられていないこととは何の関係もありません。問題は反対側にあります...接続が最初から適切に確立されず、メモリが詰まり、それぞれがスレッド/スレッドスタックを結び付けます:

  • 接続タイムアウトを減らしてみてください。
  • Executorバインドされたスレッド プールを使用して、これらの要求を実行してみてください。

AsyncTaskjavadocの内容に注意してください。

「AsyncTask は、Thread と Handler のヘルパー クラスとして設計されており、一般的なスレッド フレームワークを構成するものではありません。AsyncTasks は、理想的には短い操作 (せいぜい数秒) に使用する必要があります。スレッドを長時間実行し続ける必要がある場合は、 Executor、ThreadPoolExecutor、FutureTask など、java.util.concurrent パッケージで提供されるさまざまな API を使用することを強くお勧めします。」

于 2013-05-22T09:57:03.217 に答える