我有一个简单的代码,它向我的外部服务器发送一个 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,并出现错误:
Waiting for a blocking GC Alloc
WaitForGcToComplete blocked for 12.906ms for cause Alloc
Starting a blocking GC Alloc
Starting a blocking GC Alloc
Suspending all threads took: 35.332ms
Alloc partial concurrent mark sweep GC freed 214(21KB) AllocSpace objects, 1(200MB) LOS objects, 6% free, 216MB/232MB, paused 1.076ms total 130.115ms
Suspending all threads took: 205.400ms
Background sticky concurrent mark sweep GC freed 364(10KB) AllocSpace objects, 0(0B) LOS objects, 0% free, 416MB/416MB, paused 10.448ms total 304.325ms
Starting a blocking GC Alloc Starting a blocking GC Alloc
Alloc partial concurrent mark sweep GC freed 113(3KB) AllocSpace objects, 0(0B) LOS objects, 3% free, 416MB/432MB, paused 290us total 17.611ms
Starting a blocking GC Alloc
Alloc sticky concurrent mark sweep GC freed 31(912B) AllocSpace objects, 0(0B) LOS objects, 3% free, 416MB/432MB, paused 268us total 6.474ms
Starting a blocking GC Alloc
Alloc concurrent mark sweep GC freed 43(13KB) AllocSpace objects, 0(0B) LOS objects, 3% free, 415MB/431MB, paused 268us total 15.008ms
Forcing collection of SoftReferences for 300MB allocation
Starting a blocking GC Alloc
Alloc concurrent mark sweep GC freed 42(1256B) AllocSpace objects, 0(0B) LOS objects, 3% free, 415MB/431MB, paused 286us total 12.426ms
Throwing OutOfMemoryError "Failed to allocate a 314572860 byte allocation with 16770608 free bytes and 96MB until OOM"
当我运行下载过程时,我可以在我的设备上看到我分配了 1GB(由系统)和 600 MB 的空闲空间,而应用程序使用 20-30 MB。几秒钟后,我的应用程序开始分配越来越多的内存,我可以看到它使用了 400mb+,当达到最大值时崩溃就发生了,正如您在日志中看到的那样。
也许我不明白,但它不应该只分配所需的 100mb RAM 来存储数据 block 吗? 我几乎 100% 确定我的应用程序没有泄漏 - 下载过程正在消耗内存(肯定只调用一次)。
最佳答案
你所做的一切看起来都不奇怪,所以我查看了 LibGDX,尤其是 getResultAsString;最终你会找到 com.badlogic.gdx.utils.StreamUtils.copyStreamToString
public static String copyStreamToString (InputStream input, int estimatedSize, String charset) throws IOException {
InputStreamReader reader = charset == null ? new InputStreamReader(input) : new InputStreamReader(input, charset);
StringWriter writer = new StringWriter(Math.max(0, estimatedSize));
char[] buffer = new char[DEFAULT_BUFFER_SIZE];
int charsRead;
while ((charsRead = reader.read(buffer)) != -1) {
writer.write(buffer, 0, charsRead);
}
return writer.toString();
}
这看起来并不可怕,但我猜是 StringWriter 出了问题,导致在内部重复重新分配数组。看着this answer似乎证实了我的怀疑。
StringWriter writes to a StringBuffer internally. A StringBuffer is basically a wrapper round a char array. That array has a certain capacity. When that capacity is insufficient, StringBuffer will allocate a new larger char array and copy the contents of the previous one. At the end you call toString() on the StringWriter, which will again copy the contents of the char array into the char array of the resulting String.
所以,简而言之,您可能应该找到另一种下载文件的方法。 This question可能会有一些更强大的解决方案。
关于android - 无法使用 LibGDX Net 在 Android 上下载 100mb 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39532451/