HttpClient.execute hänger sig

Discussion in 'Frågor, support och diskussion' started by woody, Jan 31, 2011.

  1. woody

    woody Teen Droid Medlem

    Joined:
    Sep 3, 2009
    Messages:
    319
    Likes Received:
    19

    MINA ENHETER

    Hej

    En del användare av min applikation Trafikinfo.nu har rapporterat att applikationen i bland hänger sig och rar 100% CPU. Det verkar hända mycket sällan men det verkar vara i samband med att jag försöker hämta data och inget nät finns tillgängligt. Jag har fått in två krashrapporter via market med tillhörande stacktrace. Kraschen sker p.g.a. OutOfMemoryException i DefaultClientConnectionOperator.openConnection.

    Jag har försökt återskapa i emulatorer och på fysiska telefoner men inte lyckats. Då inget nätverk finns får jag alltid IOException direkt när jag försöker återskapa.

    Någon som varit med om något liknande eller kan se något fel jag gör.

    Bifogar stacktrace och koden som anropar execute. Anropen sker från en service som som håller ett WakeLock då den startats från ett intent från en AlarmMangager för återkommande uppdateringar.

    Tack på förhand.

    Anropande kod:
    Code:
        protected JSONObject DownloadJSon(String url) throws FetchInfoException, JSONException {
            Log.d(LOGTAG, "In DownloadJSon url = " + url);
            String jsonString = null;
            try {
                final int timeoutSocket = 60000;
                final int timeoutConnection = 15000;
                
                setStatus(Status.Downloading);
                
                HttpGet request = new HttpGet(url);
                HttpParams httpParameters = new BasicHttpParams();
                HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
                HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
                
                HttpClient client = new DefaultHttpClient(httpParameters);
                HttpResponse response = client.execute(request);
    
                int status = response.getStatusLine().getStatusCode();
    
                if (status != HttpStatus.SC_OK) {
                    String str = getHttpResonseString(response).trim();
                    if (str.length() > 100)
                        str = "";
                    throw new FetchInfoHttpException(url, status, str);
                }
    
                ByteArrayOutputStream outStream = new ByteArrayOutputStream();
    
                response.getEntity().writeTo(outStream);
    
                jsonString = outStream.toString();
                setStatus(Status.Parsing);
                return new JSONObject(jsonString);
    
            } catch (IOException e1) {
                Log.e(LOGTAG, "IOException in DownloadJSon.");
                Log.e(LOGTAG, "Url: " + url);
                Log.e(LOGTAG, "IOException message: " + e1.getMessage());
                throw new FetchInfoException(url,
                        ErrorCodes.IOError, e1);
            }
        }
    
    

    Stacktrace:
    Code:
    java.lang.OutOfMemoryError
    at org.apache.http.util.ByteArrayBuffer.<init>(ByteArrayBuffer.java:53)
    at org.apache.http.impl.io.AbstractSessionInputBuffer.init(AbstractSessionInputBuffer.java:82)
    at org.apache.http.impl.io.SocketInputBuffer.<init>(SocketInputBuffer.java:93)
    at org.apache.http.impl.SocketHttpClientConnection.createSessionInputBuffer(SocketHttpClientConnection.java:83)
    at org.apache.http.impl.conn.DefaultClientConnection.createSessionInputBuffer(DefaultClientConnection.java:170)
    at org.apache.http.impl.SocketHttpClientConnection.bind(SocketHttpClientConnection.java:106)
    at org.apache.http.impl.conn.DefaultClientConnection.openCompleted(DefaultClientConnection.java:129)
    at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:173)
    at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164)
    at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119)
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:348)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)
    at se.peterbjorkman.android.trafikinfo.TrafikInfoNuInfoFetcher.DownloadJSon(TrafikInfoNuInfoFetcher.java:273)
    at se.peterbjorkman.android.trafikinfo.TrafikInfoNuInfoFetcher.getSituationsByUrl(TrafikInfoNuInfoFetcher.java:338)
    at se.peterbjorkman.android.trafikinfo.TrafikInfoNuCountyFetcher.getSituations(TrafikInfoNuCountyFetcher.java:30)
    at se.peterbjorkman.android.trafikinfo.InfoFetchService$ServiceHandler.handleMessage(InfoFetchService.java:282)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:123)
    at android.os.HandlerThread.run(HandlerThread.java:60)
    
     
  2. Kaj

    Kaj Senior Droid Medlem

    Joined:
    Jun 12, 2009
    Messages:
    1 768
    Likes Received:
    44

    MINA ENHETER

    Nu brukar jag inte använda Apache http, men inget ser knasigt ut i den koden, och att du får OutOfMemoryException på det stället betyder sällan att problemet ligger där. Något annat kan mycket väl ha läckt minne, och sedan är det här allokeringen smäller.

    Vad gör du om du får FetchInfoException? Anropar du detta i en loop som spinner då?

    Det kan även vara så att du läcker i resurser i ditt hanterande av Apache http. Se stycke 1.1.5. Ensuring release of low level resources:
    http://hc.apache.org/httpcomponents-client-ga/tutorial/html/fundamentals.html
     
    woody likes this.
  3. foobar17

    foobar17 Kid Droid Medlem

    Joined:
    Jun 12, 2009
    Messages:
    56
    Likes Received:
    11

    MINA ENHETER

    Det kan vara så din applikation försöker upprepade gånger att ansluta sig (DownloadJSon), då nätverksanslutning saknas. OM så är fallet OCH i kombination med att du saknar ett viktigt anrop till client.getConnectionManager().shutdown(), SÅ byggs det upp datastrukturer som efter några gånger leder till OOME.

    Hursomhelst, var noga med att frigöra de resurser HttoClient bygger upp bakom kulisserna
    http://developer.android.com/reference/org/apache/http/conn/ClientConnectionManager.html#shutdown()
     
    woody likes this.
  4. woody

    woody Teen Droid Medlem

    Joined:
    Sep 3, 2009
    Messages:
    319
    Likes Received:
    19

    MINA ENHETER

    Tackar för svaren.

    Anropen sker inte från någon loop. Min datauppdatering avbryts direkt vid misslyckat försök.

    Känns inte som om hängningen sker här. Dålig resurshantering tycker jag inte borde resultera i 100% CPU. Jag får nog leta vidare på andra ställen.
     
  5. Kaj

    Kaj Senior Droid Medlem

    Joined:
    Jun 12, 2009
    Messages:
    1 768
    Likes Received:
    44

    MINA ENHETER

    Om man pratar om vanliga VM:ar så är det inte ovanligt att de tar 100% cpu (om man har single core) precis innan OOME kastas. Detta pga att VM:en försöker göra allt för att frigöra minne, och ju närmare minnesgränsen du kommer desto oftare kommer VM:en göra full GC, och nära slutet kommer den göra full GC konstant vilket kommer ta full cpu.

    Edit: Vet du om det händer att appen även tar 100% över längre period utan att det slutar med ett OOME?
     
    Last edited: Jan 31, 2011
  6. foobar17

    foobar17 Kid Droid Medlem

    Joined:
    Jun 12, 2009
    Messages:
    56
    Likes Received:
    11

    MINA ENHETER

    Glöm dock inte anropet till shutdown(), lämpligen placerat i ett finally block.

    Hur stora JSON mängder rör det sig om? OM det är en stor JSON fil, KAN detta vara problemet. I så fall, undersök om det går att fragmentarisera datat.
     
  7. woody

    woody Teen Droid Medlem

    Joined:
    Sep 3, 2009
    Messages:
    319
    Likes Received:
    19

    MINA ENHETER

    Buggen funnen. Var inte i närheten av nerladdningen...

    Felet låg i min uträkning av när min widget behövde uppdateras nästa gång. Viss indata gjorde att dessa beräkningar resulterade i en tidpunkt i dåtid vilket i sin tur resulterade i en oändlig loop av uppdateringsintents till widgeten...
     
  8. Kaj

    Kaj Senior Droid Medlem

    Joined:
    Jun 12, 2009
    Messages:
    1 768
    Likes Received:
    44

    MINA ENHETER

    Skönt att du hittade felet.