2017-08-01 75 views
1

IM发送大JSON来设备直通请求响应和正常的尺寸大约是5MB,所以决定使用GZIP和从5MB此下降到小于1MB内存不足上Gzip已解压缩

的问题是,即时得到内存不足我不知道在哪里发生了它的发生(我知道它在连接/响应处理程序内,但它有点偶然,我知道内存不足时可以从内存中弹出,但我认为这是主要来源)

使用改造我收到:

{ data: gzipBase64String } 

比我解压缩使用一种方法它解压缩以base64字符串和其他返回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; 
    } 

和我处理使用JsonReader这GZIPInputStream:

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

,然后将其放在一个对象

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

为什么它不工作,因为我希望这不会一次加载所有对象到内存?

+1

“使用改造我收到:'{data:gzipBase64String}'” - 在那里,你浪费了大量的内存。您的Web服务应直接返回GZip数据,而不是base64编码的,不包含在某些JSON中。现在你必须解码设备上的base64。所以你已经通过1MB的byte []'和1.3MB的base64编码数据创建了'byte []'形式的堆空间。正如Mike指出的那样,'getGzipInputStreamFromByteArray()'将返回一个5MB'byte []'。这三个巨大分配中的任何一个都可能触发'OutOfMemoryError'。 – CommonsWare

+0

@CommonsWare我知道了,但即使直接发送GZIP(不是base64),它在解码时会消耗更少的内存,或者问题依然存在?!在这一刻,即时搜索通过改造这样的事情(考虑不跨越多个GET分割数据) – user2582318

+1

“或问题仍然存在?” - 问题仍然存在,虽然它会少一些(而且你的代码运行得更快)。 “考虑不跨越多个GET分割数据” - 恕我直言,这没有任何意义。这就好像说我们不应该在Web上使用PNG和JPEG图像,并且每个网页的''标签中都应该有base64编码的图像。如果您想要执行一个GET请求,请删除JSON中的嵌入式GZip,返回完整的JSON数据集,并让您的Web服务器GZip整个响应。 – CommonsWare

回答

2

Utils.getByteArrayFromGzippedBase64(response.body().data)肯定看起来像的东西,会在内存中构建整个5 MB数组,

body = gson.fromJson(reader, ...);也肯定看起来喜欢的事,会产生相当于整个5兆值得JSON整个文本greatbighuge JSON对象在记忆中。

我会建议看看是否有任何方法可以实时缩减而不是创建一个字节数组来包含整个放气的内容。

除此之外,您可能希望考虑将您的单个greatbighuge JSON对象分解为更小的对象。

+1

谢谢@Mike Nakis,附加这个答案:https://square.github.io/retrofit/2.x/retrofit/retrofit2/http/Streaming.html – user2582318