当前位置: 首页 > 知识库问答 >
问题:

无法用LibGDX Net在Android上下载100mb文件

陈文景
2023-03-14

我有一个简单的代码,它向我的外部服务器发送一个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内存,并出现了错误:

等待阻塞GC Alloc

WaitForGcTo完全阻塞12.906毫秒,原因Alloc

启动阻塞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,总计17.611ms

启动阻塞GC Alloc

Alloc Stick并发标记扫描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

强制收集用于300MB分配的软引用

启动阻塞GC Alloc

Alloc并发标记扫描GC释放42(1256B)个AllocSpace对象,0(0B)个LOS对象,3%空闲,415MB/431MB,暂停286us总计12.426ms

抛出内存错误"分配一个314572860字节的16770608空闲字节和96MB直到OOM失败"

当我运行下载过程时,我可以在我的设备上看到我分配了1GB(按系统)和600 mb的空闲空间,而html" target="_blank">应用程序使用了20-30 mb。几秒钟后,我的应用程序开始分配越来越多的内存,我可以看到,它使用了400mb,当达到最大值时就会崩溃,正如你在日志中看到的那样。

也许我不明白,但它不应该只分配所需的100mb内存来存储数据块吗?我几乎100%确定我的应用程序没有泄漏——下载过程消耗了内存(当然只调用了一次)。

共有1个答案

邢硕
2023-03-14

你所做的一切看起来都不奇怪,所以我看了一下LibGDX,尤其是getResultAsString;最终,你会进入com。糟糕的逻辑。gdx。乌提尔斯。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出现了问题,导致数组在内部重复重新分配。看着这个答案似乎证实了我的怀疑。

StringWriter在内部写入StringBuffer。StringBuffer基本上是一个字符数组的包装器。该数组有一定的容量。当容量不足时,StringBuffer将分配一个新的更大的字符数组并复制前一个的内容。最后,您在StringWriter上调用toString(),它将再次将字符数组的内容复制到结果String的字符数组中。

因此,简而言之,您可能应该找到另一种下载文件的方法。这个问题可能有一些更可靠的解决方案。

 类似资料:
  • 我正在使用CKEditor插件将图像上传到我的OpenShift应用程序,但该应用程序不会上传文件。它在本地运行良好,但我无法确定是什么导致了这个问题。它似乎找不到目录。 == {err:{[Error: ENOENT, open'/var/lib/openShift/57cdb2770c1e660d0b000003/app-root/runtime/repo/路由来/.../Public/上传/

  • 我正在使用chromedriver和selenium从应用程序下载文件。但当点击应用程序中的下载按钮时,它给出的错误是“” Chromedriver版本:2.21硒版本:2.53.0 初始化chrome驱动和更改下载位置的代码: 错误是: 有人能帮我吗?我可以手动从Chrome下载文件。

  • 我想上传100MB以上的文件。

  • 我使用Maven和surefire插件通过扩展AbstractTestNGSpringContextTests来运行TestNG测试,结果显示,即使上下文在类路径中也没有加载,并且测试在我的ide中正常工作,但在Maven中不行。 @contextConfiguration(locations=Array(“classpath*:/com/gottex/gottware/server/offlin

  • 我需要从服务器下载一个文本文件,并将其保存在内存中。然后一行行地去读。更好的是直接从服务器逐行离读。 编辑:“将其保存在内存中”的意思是不将其写入文件。 你会怎么做? 谢谢!

  • Cloudera是否有任何特殊的设置导致了这种情况?