Domanda

Ho ricevuto alcuni rapporti dagli utenti di arresti anomali quando prova a utilizzare la mia applicazione sul 4G/LTE di Verizon.

Guardando la traccia dello stack, sembra che l'implementazione di HttpClient.execute () di Android stia lanciando un OOM. Ciò accade solo su dispositivi 4G/LTE, in particolare HTC Thunderbolt, e solo quando su 4G/LTE. Wifi, 3G, Umts sono ok. Funziona bene anche sulle cose WiMax 4G di Sprint funzionano bene.

Due domande:

  • Qual è il modo migliore per attirare l'attenzione degli sviluppatori Android su questo? Eventuali opzioni migliori rispetto a segnalare http://code.google.com/p/android/issues?

  • Qualche idea su come posso aggirare questo? Non ho un dispositivo 4G da solo e non riesco a far sì che ciò accada nell'emulatore, quindi devo fare alcune ipotesi educate qui. Posso provare a catturare l'OOM nel mio codice e tentare di pulire e forzare GC, ma non sono sicuro che sia una buona idea. Commenti o altri suggerimenti?

Ecco cosa sta facendo il mio codice:

    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 );

    ...

Ecco la traccia dello stack che si schianta:

E/Dalvikvm-HEAP (11639): fuori memoria su un'allocazione 2055696 byte. I/Dalvikvm (11639): "thread-16" prio = 5 tid = 9 runnable i/dalvikvm (11639): | Gruppo = "Main" SCOUNT = 0 DScount = 0 S = N OBJ = 0x48563070 self = 0x3C4340 I/Dalvikvm (11639): | systid = 11682 Nizza = 0 Sched = 0/0 CGRP = Handle predefinito = 3948760 I/Dalvikvm (11639): | SchedStat = (208709711 74005130 214)

I/Dalvikvm (11639): su org.apache.http.impl.io.abstractSessioninputBuffer.init (AbstractSessionInputBuffer.java:~79) I/Dalvikvm (11639): su org.apache.http.iMpl.io.socketInputfer. ( SocketInputBuffer.java:93) I/Dalvikvm (11639): su org.apache.http.impl.sockethtttpclientconnection.createsessioninputBuffer (SockethttpClientConnection.java:83) i/Dalvikvm (11639): a Org.apache.HTP.apache. DefaultClientConnection.CreateSessionInputBuffer (defaultClientConnection.java:170) I/Dalvikvm (11639): su org.apache.http.impl.sockethtpclientConnection.bind (SockethtpclientConnection.java:106) i/DalvikvM (11639) Impl.Conn.DefaultClientConnection.OPencompleted (defaultClientConnection.java:129) I/Dalvikvm (11639): su org.apache.http.impl.conn.DefaultClientConnectionOperator.OPenConnection (defaultClientConnection.java:173) org.apache.http.impl.conn.abstractpoolentry.open (AbstractPoolentry.java:164) I/Dalvikvm (11639): su org.apache.http.impl.conn.abstractpooledc onnadapter.open (AbstractPooledConnadapter.java:119) I/Dalvikvm (11639): su org.apache.http.impl.client.defaultrequestDirector.execute (defaultrEstDirector.java:348) I/Dalvikvm (11639: a Org.apche. http.impl.client.abstracthttpclient.execute (Abstracthttpclient.java:555) i/Dalvikvm (11639): su org.apache.http.impl.client.abstracthttpclient.execute (AsctTracthtpclient.java:487) i/datalvik (11639) : su org.apache.http.impl.client.abstracthttpclient.execute (Abstracthttpclient.java:465) I/Dalvikvm (11639): at com.myapplication.fetcher.trysourcefetch (fetcher.java:205) i/Dalvikvm (11639) : at com.myapplication.fetcher.run (fetcher.java:298) I/Dalvikvm (11639): su java.lang.thread.run (thread.java:1102) I/Dalvikvm (11639): E/Dalvikvm (11639 ): Fuori dalla memoria: dimensione del heap = 24171kb, allocato = 23142kb, dimensione Bitmap = 59kb, limite = 21884kb e/Dalvikvm (11639): Informazioni extra: footprint = 24327kb, footprint consentito = 24519kb, trimmed = 348kb W/Dalvikvm (11639 ?

È stato utile?

Soluzione

Guardando la traccia dello stack, sembra che l'implementazione di HttpClient.execute () di Android stia lanciando un OOM.

Ciò non è indicato dalla traccia dello stack che hai sulla questione. Certo, non hai fornito l'intera traccia dello stack sul problema.

Qual è il modo migliore per attirare l'attenzione degli sviluppatori Android su questo? Eventuali opzioni migliori rispetto a segnalare http://code.google.com/p/android/issues?

Le probabilità che questo sia un puro bug Android sono piccoli, sebbene non zero.

Ecco alcune altre possibilità, in nessun ordine particolare:

  1. Non ci sono problemi con execute() Di per sé, ma che stai semplicemente esaurendo la memoria e le tracce dello stack che hai incontrato lo stanno semplicemente dimostrando execute() Sta sottolineando il tuo mucchio.

  2. Il problema è in alcune modifiche che HTC ha apportato ad Android per il fulmine, probabilmente entrando in vigore solo quando sulla rete LTE.

  3. Il problema è in qualche modo causato dalla stessa rete di Verizon LTE (ad esempio, un proxy delle loro informazioni di manding a vite che sta causando un connipzione HTTPClient).

Qualche idea su come posso aggirare questo?

Innanzitutto, userei strumenti esistenti (ad es. Dumping HProf ed esame con tappetini Eclipse) per confermare che non hai una perdita di memoria in generale che la combinazione Thunderbolt/LTE sembra inciampare.

Successivamente, ti consiglio di trovare un modo per riprodurre costantemente l'errore. Potrebbe essere la tua app esistente con una serie di passaggi da seguire, oppure potrebbe essere un'app dedicata (ad esempio, registrare l'URL che innesca l'OOM, quindi crea una piccola app che fa solo quella richiesta httpclient). Vorrei che Deviceanywhere avesse un fulmine, ma non sembra così. Metterò fuori qualche sentimento e vedrò se riesco a ottenere un po 'di aiuto su quel fronte.

In termini di lavorarci atto android.os.Build dati, e forse che sei su LTE tramite ConnectivityManager (Immagino che LTE elencherebbe come WiMax, ma è solo un'ipotesi) e avvertirà gli utenti dei problemi con quella combinazione.

Oltre a ciò, puoi provare a cambiare un po 'il tuo utilizzo di HttpClient e vedere se ha un effetto, come ad esempio:

  • Se stai supportando solo il livello API 8 o superiore, potresti dare AndroidHttpClient uno scatto come sostituto drop-in
  • Disabilita l'accesso multi-thread (in generale o specifico per il fulmine) e sbarazzarsi del ThreadSafeClientConnManager

Mi dispiace di non avere una risposta "Magic Bullet" per te qui.


AGGIORNARE

Ora che ho la traccia completa dello stack, guardare attraverso il codice sorgente è ... illuminante, in qualche modo.

Il problema sembra essere quello:

HttpConnectionParams.getSocketBufferSize(params);

sta restituendo quel valore circa 2 MB che sta innescando l'OOM. Questo è un buffer terribilmente grande, in particolare per il motore Dalvik GC, che può essere frammentato (sì, c'è di nuovo quella parola).

params Ecco il HttpParams. Sembra che tu stia creando quelli da solo tramite getHttpParams(). Per esempio, AndroidHttpClient Lo imposta su 8192:

HttpConnectionParams.setSocketBufferSize(params, 8192);

Se stai impostando tu stesso la dimensione del buffer socket, prova a ridurla. In caso contrario, prova a impostarlo su 8192 e vedi se questo aiuta.

Altri suggerimenti

Ecco la correzione: https://review.source.android.com/22852

Nel frattempo, l'URLConnection è immune. È solo httpclient che ha questo problema.

Se sei uno sviluppatore che desidera testare questo tipo di fallimento, puoi usare "ADB Shell setProp" per impostare, diciamo "net.tcp.Buffersize.Wifi" in modo che le dimensioni del buffer di lettura/scrittura massima siano enormi quando il tuo Il dispositivo è su WiFi. Qualcosa come il seguente sarebbe un vero test di stress:

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

È questo tipo di modifica della configurazione che esercita il bug HttpClient. Non so quali siano i valori esatti sul fulmine, ma qualcuno con il dispositivo potrebbe scoprire usando "ADB Shell GetProp | Grep BufferSize".

Forse questo aiuterà:

// 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);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top