21

Verizonの4G/LTEでアプリケーションを使用しようとすると、クラッシュのユーザーからいくつかの報告があります。

スタックトレースを見ると、AndroidのHttpClient.execute()実装がOOMをスローしているように見えます。これは、4G / LTEデバイス、特にHTC Thunderboltでのみ発生し、4G/LTEでのみ発生します。WiFi、3G、UMTSはOKです。SprintのWiMax4Gでも問題なく動作します。

2つの質問:

  • これについてAndroid開発者の注意を引くための最良の方法は何ですか?http://code.google.com/p/android/issuesで報告するよりも良いオプションはありますか?

  • これを回避する方法について何かアイデアはありますか?私自身は4Gデバイスを持っておらず、エミュレーターでこれを実現できないため、ここで知識に基づいた推測を行う必要があります。コードでOOMをキャッチし、クリーンアップしてGCを強制することはできますが、それが良いアイデアかどうかはわかりません。コメントやその他の提案?

これが私のコードがしていることです:

    HttpParams params = this.getHttpParams(); // returns params
    ClientConnectionManager cm = new ThreadSafeClientConnManager(params, this.getHttpSchemeRegistry() );
    DefaultHttpClient httpClient = new DefaultHttpClient( cm, params );

    HttpResponse response = null;
    request = new HttpGet( url );

    try {

        response = httpClient.execute(request); // <-- OOM on 4G/LTE. OK otherwise
        int statusCode = response.getStatusLine().getStatusCode();
        Log.i("fetcher", "execute returned, http status " + statusCode );

    ...

クラッシュするスタックトレースは次のとおりです。

E / dalvikvm-heap(11639):2055696バイトの割り当てでメモリ不足。I / dalvikvm(11639):"スレッド-16"prio = 5 tid=9実行可能I/dalvikvm(11639):| group = "main" sCount = 0 dsCount = 0 s = N obj = 0x48563070 self = 0x3c4340 I / dalvikvm(11639):| sysTid = 11682 nice = 0 sched = 0/0 cgrp = default handle = 3948760 I / dalvikvm(11639):| schedstat =(208709711 74005130 214)

I / dalvikvm(11639):org.apache.http.impl.io.AbstractSessionInputBuffer.init(AbstractSessionInputBuffer.java:~79)I / dalvikvm(11639):org.apache.http.impl.io.SocketInputBuffer。( SocketInputBuffer.java:93)I / dalvikvm(11639):org.apache.http.impl.SocketHttpClientConnection.createSessionInputBuffer(SocketHttpClientConnection.java:83)I / dalvikvm(11639):org.apache.http.impl.connで。 DefaultClientConnection.createSessionInputBuffer(DefaultClientConnection.java:170)I / dalvikvm(11639):org.apache.http.impl.SocketHttpClientConnection.bind(SocketHttpClientConnection.java:106)I / dalvikvm(11639):org.apache.httpで。 impl.conn.DefaultClientConnection.openCompleted(DefaultClientConnection.java:129)I / dalvikvm(11639):org.apache.http.impl.conn.DefaultClientConnectionOperatorにあります。openConnection(DefaultClientConnectionOperator.java:173)I / dalvikvm(11639):org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164)I / dalvikvm(11639):org.apache.httpで。 impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119)I / dalvikvm(11639):org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:348)I / dalvikvm(11639):at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)I / dalvikvm(11639):org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)I / dalvikvm(11639):org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)I / dalvikvm(11639):com.myapplication.Fetcher.trySourceFetch(Fetcher.java:205)I / dalvikvm(11639):comで。myapplication.Fetcher.run(Fetcher.java:298)I / dalvikvm(11639):java.lang.Thread.run(Thread.java:1102)でI / dalvikvm(11639):E / dalvikvm(11639):メモリ:ヒープサイズ= 24171KB、割り当て済み= 23142KB、ビットマップサイズ= 59KB、制限= 21884KB E / dalvikvm(11639):追加情報:フットプリント= 24327KB、許可されたフットプリント= 24519KB、トリミング= 348KB W / dalvikvm(11639):threadid = 9:キャッチされない例外でスレッドが終了します(group = 0x40025b38)キャッチされない例外で終了するスレッド(group = 0x40025b38)キャッチされない例外で終了するスレッド(group = 0x40025b38)

4

3 に答える 3

26

スタックトレースを見ると、AndroidのHttpClient.execute()実装がOOMをスローしているように見えます。

これは、問題に関するスタックトレースでは示されません。もちろん、この問題に関するスタックトレース全体を提供したわけではありません。

これについてAndroid開発者の注意を引くための最良の方法は何ですか?http://code.google.com/p/android/issuesで報告するよりも良いオプションはありますか?

これが純粋なAndroidバグである可能性は低いですが、ゼロではありません。

他のいくつかの可能性がありますが、順不同です。

  1. execute()それ自体は問題ありませんが、単にメモリが不足しているだけであり、遭遇したスタックトレースは、それexecute()がヒープにストレスを与えていることを示しているにすぎません。

  2. 問題は、HTCがThunderbolt用にAndroidに加えたいくつかの変更にあり、LTEネットワーク上でのみ有効になる可能性があります。

  3. この問題は、Verizon LTEネットワーク自体が原因で発生します(たとえば、HttpClientに接続を許可しているスクリューボール情報を送り返すプロキシなど)。

これを回避する方法について何かアイデアはありますか?

まず、既存のツール(HPROFのダンプやEclipse MATでの調査など)を使用して、Thunderbolt/LTEコンボがつまずいたように見える一般的なメモリリークがないことを確認します。

次に、エラーを一貫して再現する方法を考え出すことをお勧めします。これは、一連の手順を実行する既存のアプリの場合もあれば、専用アプリの場合もあります(たとえば、OOMをトリガーするURLをログに記録し、そのHttpClient要求を実行する小さなアプリを作成します)。DeviceAnywhereにThunderboltがあればいいのですが、そうではありません。私はいくつかの触手を出し、その面で助けを得ることができるかどうかを確認します。

それを回避するという点では、一時的なものとして、android.os.Buildデータを介してThunderboltで実行していること、およびおそらくLTEを介して実行していることを検出できますConnectivityManager(LTEはWiMAXとしてリストされると思いますが、それは単なる推測です)、そのコンボの問題についてユーザーに警告します。

それ以外にも、HttpClientの使用法を少し変更して、次のような効果があるかどうかを確認できます。

  • APIレベル8以上のみをサポートしている場合はAndroidHttpClient、ドロップインの代替としてショットを与えることができます
  • マルチスレッドアクセス(一般的またはThunderbolt固有)を無効にして、ThreadSafeClientConnManager

ここに「魔法の弾丸」の答えがないことをお詫び申し上げます。


アップデート

完全なスタックトレースができたので、ソースコードを調べると...多少わかりやすくなります。

問題は次のように思われます。

HttpConnectionParams.getSocketBufferSize(params);

OOMをトリガーしている2MB程度の値を返しています。これは非常に大きなバッファであり、特にDalvik GCエンジンの場合、断片化される可能性があります(はい、その言葉が再びあります)。

paramsこれがですHttpParams。を介して自分で作成しているようですgetHttpParams()。たとえば、AndroidHttpClientこれを8192に設定します。

HttpConnectionParams.setSocketBufferSize(params, 8192);

ソケットバッファサイズを自分で設定する場合は、それを減らしてみてください。そうでない場合は、8192に設定してみて、それが役立つかどうかを確認してください。

于 2011-03-18T22:09:56.580 に答える
4

修正方法は次のとおりです:https ://review.source.android.com/22852

その間、URLConnectionは影響を受けません。この問題を抱えているのはHttpClientだけです。

この種の障害をテストしたい開発者の場合は、「adb shell setprop」を使用して、たとえば「net.tcp.buffersize.wifi」を設定し、読み取り/書き込みソケットの最大バッファーサイズが非常に大きくなるようにすることができます。デバイスはwifi上にあります。次のようなものは、実際のストレステストになります。

adb shell setprop net.tcp.buffersize.wifi 4096,80999999,80999999,4096,80999999,80999999

HttpClientのバグを引き起こすのは、この種の構成変更です。Thunderboltの正確な値はわかりませんが、デバイスを持っている人は「adb shell getprop|grepbuffersize」を使用して見つけることができます。

于 2011-05-14T01:18:30.547 に答える
3

多分これは役立つでしょう:

// Set the timeout in milliseconds until a connection is established.
int timeoutConnection = 5000;

// Set the default socket timeout (SO_TIMEOUT) 
// in milliseconds which is the timeout for waiting for data.
int timeoutSocket = 4000;

// set timeout parameters for HttpClient 
HttpParams httpParameters = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
HttpConnectionParams.setSocketBufferSize(httpParameters, 8192);//setting setSocketBufferSize

DefaultHttpClient httpClient = new DefaultHttpClient();
httpClient.setParams(httpParameters);
于 2011-06-08T10:35:29.367 に答える