2017-08-01 11 views
1

イム要求応答スルーデバイスへの大規模なJSONを送信すると、通常サイズが5メガバイトの周りにあるので、私はGZIPを使用することを決め、これが未満1メガバイトのOutOfMemoryが

に5メガバイトから落下した問題は、イムがOutOfMemoryを取得していることである解凍します私は正確には知っていません(私はその内部の接続/応答ハンドラを知っていますが、メモリが不足しているとどこからでもメモリが不足していることが分かっていますが、これがメインソースだと思います)

レトロフィットを使用してください:

私はそれが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; 
    } 

を返すためにbase64文字列を解凍する一つの方法を使用して、その他の解凍と私はJsonReaderを使用してこのGZIPInputStreamを扱うよりも、

:その後、

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

と内側に置きますオブジェクト

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

なぜ私はこれがすべてのオブジェクトを一度にメモリに読み込まないことを望んでいたので、それはうまくいかなかったのですか?

+1

"改造を使用すると、{{data:gzipBase64String}}"というメッセージが表示されます。 - そこには、大量のメモリが浪費されています。 Webサービスはbase64でエンコードされたものではなく、JSONにラップされないGZipデータを直接返す必要があります。これで、デバイス上のbase64をデコードする必要があります。だから、既に2.3MBのヒープスペースを、1MBのbyte [] 'と、' byte [] 'を作成した〜1.3MBのbase64でエンコードされたデータのStringの形で吹き飛ばしています。 Mikeが指摘するように、 'getGzipInputStreamFromByteArray()'は5MBの 'byte []'を返します。これらの3つの巨大な割り当てのうちのどれかが 'OutOfMemoryError'を引き起こすかもしれません。 – CommonsWare

+0

@CommonsWare私はそれを持っていますが、GZIPを直接(base64ではなく)送信すると、デコード時のメモリ消費が少なくなるか、問題はまだ存在しますか?現時点では、このようなものを改造して検索しています(複数のGETにデータを分割しないことを考慮) – user2582318

+1

"または問題はまだ存在しますか? - 問題はまだ存在しますが、コードは少し遅くなります(コードはより速く実行されます)。 "複数のGETにまたがってデータを分割しないことを検討する" - IMHO、それは意味をなさない。これは、Web上にPNGやJPEGの画像を置いてはならず、すべてのWebページにbase64でエンコードされた画像が ''タグに含まれている必要があるということに似ています。 1つのGETリクエストを行いたい場合は、JSONに埋め込まれたGZipを取り除き、完全なJSONデータセットを返し、WebサーバーにGzip全体の応答を持たせます。 – CommonsWare

答えて

2

Utils.getByteArrayFromGzippedBase64(response.body().data)は間違いなくメモリ内全体を5メガバイトの配列を構築何かのように見える、と

body = gson.fromJson(reader, ...);も間違いなくJSONテキストの価値は全体の5メガバイトに対応して全体greatbighugeのJSONオブジェクトを生成すると何かのように見えますメモリ内にある。

デフレートされたコンテンツ全体を格納するためにバイト配列を作成するのではなく、オンザフライでデフレートする方法があるかどうかを確認することをお勧めします。

これ以外にも、1つのgreatbighuge JSONオブジェクトを小さなオブジェクトに分割することができます。

+1

@Mike Nakis、この回答を追加していただきありがとうございます:https://square.github.io/retrofit/2.x/retrofit/retrofit2/http/Streaming.html – user2582318