2017-08-01 2 views
1

im großen json zu Gerät durch Anforderung Antwort zu senden und in der Regel die Größe ist etwa 5 MB, so habe ich beschlossen, GZIP zu verwenden und dies fiel von 5 MB auf weniger als 1MBOutOfMemory auf gzip dekomprimiert

Das Problem ist, dass im immer OutOfMemory und ich weiß nicht, wo genau es passiert (ich weiß es innerhalb der Verbindung/Antwort-Handler, aber es ist ein wenig aleatorischen wo, ich weiß aus dem Speicher kann von überall aus knallen, wenn der Speicher niedrig ist, aber ich denke, das ist die Hauptquelle)

Mit Nachrüstung erhalte ich:

{ data: gzipBase64String } 

als i dekomprimieren es ein Verfahren unter Verwendung der Base64-String und die andere dekomprimiert die GZIPInputStream

public static GZIPInputStream getByteArrayFromGzippedBase64(String base64) throws IOException { 
     if(base64 != null) { 
      try { 
       byte[] data = Base64.decode(base64, Base64.DEFAULT); 
       if (data != null) { 
        return getGzipInputStreamFromByteArray(data); 
       } 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
     return null; 
    } 

    public static GZIPInputStream getGzipInputStreamFromByteArray(byte[] compressed) throws IOException { 
     final int BUFFER_SIZE = 32; 
     ByteArrayInputStream is = new ByteArrayInputStream(compressed); 
     GZIPInputStream gis = new GZIPInputStream(is, BUFFER_SIZE); 
     return gis; 
    } 

und i handhaben diese GZIPInputStream mit einem JsonReader zurückzukehren:

reader = new JsonReader(new InputStreamReader(Utils.getByteArrayFromGzippedBase64(response.body().data))); 

und dann innerhalb einer Put objekt

body = gson.fromJson(reader, SyncDayjourneysResponse.class); 

warum funktioniert es nicht, da ich gehofft hatte, dass dies nicht alle objekte auf speicher laden?

+1

"Mit Retrofit erhalte ich:' {data: gzipBase64String} '" - genau dort verschwenden Sie eine Menge Speicher. Ihr Webdienst sollte die GZip-Daten direkt zurückgeben, nicht base64-codiert, nicht in JSON verpackt. Und jetzt musst du das base64 auf dem Gerät dekodieren. Sie haben also bereits 2,3 MB Heapspeicher in Form eines 1 MB 'byte []' und eines ~ 1,3MB 'String' von base64-codierten Daten, die das' byte [] 'erzeugt haben, durchgebrannt. Wie Mike hervorhebt, wird 'getGzipInputStreamFromByteArray()' ein 5MB 'Byte []' zurückgeben. Jede dieser drei großen Zuordnungen kann einen "OutOfMemoryError" auslösen. – CommonsWare

+0

@CommonsWare ich habe es, aber senden sogar die GZIP direkt (nicht base64) wird es weniger Speicher bei der Decodierung verbrauchen oder das Problem besteht noch ?! In diesem Moment suche ich durch Retrofit etwas wie dieses (in Erwägung, die Daten nicht über mehrere GET zu teilen) – user2582318

+1

"oder das Problem besteht noch?" - Das Problem wird weiterhin bestehen, obwohl es etwas weniger wahrscheinlich ist (und Ihr Code wird schneller ausgeführt). "in Erwägung ziehen, die Daten nicht über mehrere GET zu teilen" - IMHO, das macht keinen Sinn. Das ist vergleichbar mit der Aussage, dass wir keine PNG- und JPEG-Bilder im Web haben sollten und dass jede Webseite base64-kodierte Bilder in ihren '' Tags haben sollte. Wenn Sie eine GET-Anforderung ausführen möchten, entfernen Sie das eingebettete GZip im JSON, geben Sie das vollständige JSON-Dataset zurück und lassen Sie Ihren Webserver die gesamte Antwort mit GZip ausführen. – CommonsWare

Antwort

2

Utils.getByteArrayFromGzippedBase64(response.body().data) sieht definitiv wie etwas, das das ganze 5 MB Array im Speicher aufbauen würde, und

body = gson.fromJson(reader, ...); auch sieht definitiv wie etwas, das ein ganzes greatbighuge JSON-Objekt, das auf ein ganzen 5 Megabyte im Wert von JSON Text entspricht erzeugen würde in Erinnerung.

Ich würde empfehlen, zu sehen, ob es eine Möglichkeit gibt, das Deflaten on-the-fly durchzuführen, anstatt ein Byte-Array zu erstellen, das den gesamten entleerten Inhalt enthält.

Darüber hinaus möchten Sie möglicherweise untersuchen, wie Sie Ihr einzelnes Jig-Großbuchstaben-JSON-Objekt in kleinere Objekte aufteilen.

+1

Danke @Mike Nakis, mit dieser Antwort anfügen: https://square.github.io/retrofit/2.x/retrofit/retrofit2/http/Streaming.html – user2582318