我有一个简单的代码,它向我的外部服务器发送一个Http请求,以下载大小为100mb的.txt文件。较小的文件,如40mb正在工作,但是较大的文件存在一些问题。让我给你看一些代码:
Net.HttpRequest request = new Net.HttpRequest(Net.HttpMethods.GET);
request.setTimeOut(2500);
String assetsUrl = "http://111.111.111.111/100mb.txt";
request.setUrl(assetsUrl);
// Send the request, listen for the response
// Asynchronously
Gdx.net.sendHttpRequest(request, new Net.HttpResponseListener() {
@Override
public void handleHttpResponse (Net.HttpResponse httpResponse) {
InputStream is = httpResponse.getResultAsStream();
OutputStream os = Gdx.files.local("100mb.txt").write(false);
byte[] bytes = new byte[1024];
int count = -1;
try {
while ((count = is.read(bytes, 0, bytes.length)) != -1) {
os.write(bytes, 0, count);
}
} catch (IOException e) {
e.printStackTrace();
}
}
还有一些代码可以显示进度,但这里并不重要。 问题是该文件的大小为100mb,但Android在下载时神奇地分配了400mb + RAM并带有错误:
等待阻止GC Alloc
WaitForGcToComplete因为Alloc
而被阻止了12.906ms启动阻止GC Alloc
启动阻止GC Alloc
暂停所有线程:35.332ms
Alloc部分并发标记扫描GC释放214(21KB)AllocSpace 对象,1(200MB)LOS对象,6%免费,216MB / 232MB,暂停1.076ms 总计130.115ms
暂停所有线程:205.400ms
后台粘性并发标记扫描GC释放364(10KB)AllocSpace 对象,0(0B)LOS对象,0%免费,416MB / 416MB,暂停10.448ms 总计304.325ms
启动阻止GC Alloc启动阻止GC Alloc
Alloc部分并发标记扫描GC释放113(3KB)AllocSpace 对象,0(0B)LOS对象,3%免费,416MB / 432MB,总计暂停290us 17.611ms
启动阻止GC Alloc
Alloc粘性并发标记扫描GC释放31(912B)AllocSpace 对象,0(0B)LOS对象,3%免费,416MB / 432MB,暂停268us 6.474ms
启动阻止GC Alloc
Alloc并发标记扫描GC释放43(13KB)AllocSpace对象, 0(0B)LOS对象,3%免费,415MB / 431MB,暂停268us总计15.008ms
强制收集300位分配的SoftReferences
启动阻止GC Alloc
Alloc并发标记扫描GC释放了42个(1256B)AllocSpace对象, 0(0B)LOS对象,3%免费,415MB / 431MB,暂停286us总计12.426ms
抛出OutOfMemoryError“无法分配314572860字节 分配16770608个空闲字节和96MB直到OOM“
当我运行下载过程时,我可以在我的设备上看到我分配了1GB(按系统分配)和600 MB免费,而应用程序使用20-30 mb。几秒钟之后,我的应用程序开始分配越来越多的内存,我可以看到,它使用了400mb +,当它达到最大值时会出现崩溃,就像你在日志中看到的那样。
也许我不理解它,但它不应该只分配所需的100mb RAM来存储数据块吗? 我几乎100%确定我的应用程序没有泄漏 - 下载过程正在消耗内存(肯定只能调用一次)。
答案 0 :(得分:1)
你所做的一切都看起来很奇怪,所以我看了一下LibGDX,特别是getResultAsString;最后你得到 com.badlogic.gdx.utils.StreamUtils.copyStreamToString
agent_review.reviewer
这看起来并不可怕,但我的猜测是StringWriter正在发生的事情,导致内部重复重新分配数组。看this answer似乎证实了我的怀疑。
StringWriter在内部写入StringBuffer。 StringBuffer基本上是一个char数组的包装器。该阵列具有一定的容量。当容量不足时,StringBuffer将分配一个新的更大的char数组并复制前一个的内容。最后,在StringWriter上调用toString(),它将再次将char数组的内容复制到生成的String的char数组中。
因此,简而言之,您应该找到另一种下载文件的方法。 This question可能会有更强大的解决方案。