【问题标题】:Download large files using large byte array causes "Out of memory"使用大字节数组下载大文件导致“内存不足”
【发布时间】:2015-10-02 14:33:20
【问题描述】:

我想使用流下载一个 100MB 的文件:
我使用 AsyncTask 类进行下载:

    @Override
    protected Void doInBackground(String... params) {
        try {
            URL url = new URL(params[0]);
            connection = (HttpURLConnection) url.openConnection();
            connection.connect();
            inputStream = connection.getInputStream();
            outputStream = new FileOutputStream(new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), params[1]));
            byte[] data = new byte[104857600];
            int length = inputStream.read(data);
            outputStream.write(data, 0, length);
        } catch (Exception e) {
            Log.e(TAG, "Unable to download file with DownloadTask: " + e.getMessage());
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
                if (outputStream != null) {
                    outputStream.close();
                }
                connection.disconnect();
            } catch (Exception e) {
                Log.e(TAG, "Unable to cancel download file with DownloadTask: " + e.getMessage());
            }
        }
        return null;
    }

我确定我使用了以下权限:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

但是当我测试我的应用程序时,它崩溃了,我在 logcat Out of memory on a 104857616-byte allocation 中看到:

10-02 10:28:35.578 29630-2246/com.example.myapp E/dalvikvm-heap: Out of memory on a 104857616-byte allocation.
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime: java.lang.RuntimeException: An error occured while executing doInBackground()
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime:     at android.os.AsyncTask$3.done(AsyncTask.java:299)
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime:     at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:352)
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime:     at java.util.concurrent.FutureTask.setException(FutureTask.java:219)
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime:     at java.util.concurrent.FutureTask.run(FutureTask.java:239)
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime:     at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime:     at java.lang.Thread.run(Thread.java:856)
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime:  Caused by: java.lang.OutOfMemoryError
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime:     at com.example.myapp.DownloaderActivity$DownloadTask.doInBackground(DownloaderActivity.java:126)
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime:     at com.example.myapp.DownloaderActivity$DownloadTask.doInBackground(DownloaderActivity.java:107)
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime:     at android.os.AsyncTask$2.call(AsyncTask.java:287)
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime:     at java.util.concurrent.FutureTask.run(FutureTask.java:234)
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime:     at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230) 
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080) 
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573) 
10-02 10:28:35.601 29630-2246/com.example.myapp E/AndroidRuntime:     at java.lang.Thread.run(Thread.java:856)

有没有办法下载大文件或接受 104857600 字节 (100MB)?

【问题讨论】:

  • 你必须分块下载文件
  • 不要批量分配内存。分块分配内存并下载。
  • 更明确地说,使用较小的字节数组作为缓冲区,例如 1KB。您可以随时尝试使用哪种缓冲区大小可以获得最佳性能。
  • 亲爱的@CarlosBorau,这对OOM有什么帮助?
  • 我想我完全误解了这个问题,我很抱歉@Selvin!我会删除的东西

标签: java android android-asynctask bytearray httpurlconnection


【解决方案1】:

您已将数据部分作为块写入。系统不会一次为操作提供大量内存。

替换那些行:

byte[] data = new byte[104857600];
int length = inputStream.read(data);
outputStream.write(data, 0, length);

作者:

byte [] buffer = new byte[1024];
int bytesRead = 0;
while((bytesRead =input.read(buffer)) != -1) {
outputStream .write(buffer, 0,
bytesRead);
}

【讨论】:

  • 非常感谢!!!,现在我明白为什么下载时文件会出现在资源管理器中
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-02-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-28
  • 2012-06-16
  • 2011-07-16
相关资源
最近更新 更多