Android下载文件内存不足的问题
Posted
技术标签:
【中文标题】Android下载文件内存不足的问题【英文标题】:Android download file out of memory woes 【发布时间】:2010-10-28 16:27:29 【问题描述】:我正在尝试下载一个开始时小于 22 mb 的 zip 文件。在出现这些异常后,我更改了默认的 BufferedInputStream,但仍然出现内存不足的错误。
public void downloadFromUrl(String fileName)
//avoid unknown host exception
try
InetAddress i = InetAddress
.getByName("http://xxx/android/" + fileName);
catch (UnknownHostException e1)
e1.printStackTrace();
try
URL url = new URL("http://xxx/Android/" + fileName);
File file = new File(fileName);
long startTime = System.currentTimeMillis();
Log.d("DownloadManager", "download begining");
Log.d("DownloadManager", "download url:" + url);
Log.d("DownloadManager", "downloaded file name:" + fileName);
URLConnection ucon = url.openConnection();
InputStream is = ucon.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is, 23 * 1024);
ByteArrayBuffer baf = new ByteArrayBuffer(23 * 1024);
int current = 0;
while ((current = bis.read()) != -1)
baf.append((byte) current);
FileOutputStream fos = new FileOutputStream(file);
fos.write(baf.toByteArray());
fos.close();
Log.d("DownloadManager",
"download ready in"
+ ((System.currentTimeMillis() - startTime) / 1000)
+ " sec");
catch (IOException e)
Log.d("DownloadManager", "Error: " + e);
堆栈:
10-28 10:18:16.885: DEBUG/ImageManager(1804): download begining
10-28 10:18:16.885: DEBUG/ImageManager(1804): download url:http://xxx/Android/Samples.zip
10-28 10:18:16.885: DEBUG/ImageManager(1804): downloaded file name:Samples.zip
10-28 10:18:17.204: INFO/global(1804): Default buffer size used in BufferedInputStream constructor. It would be better to be explicit if an 8k buffer is required.
10-28 10:18:17.845: DEBUG/dalvikvm(1804): GC_FOR_MALLOC freed 1803 objects / 185168 bytes in 96ms
10-28 10:18:18.415: DEBUG/dalvikvm(1804): GC_FOR_MALLOC freed 229 objects / 105296 bytes in 78ms
10-28 10:18:18.425: INFO/dalvikvm-heap(1804): Grow heap (frag case) to 3.184MB for 376848-byte allocation
10-28 10:18:18.545: DEBUG/dalvikvm(1804): GC_FOR_MALLOC freed 0 objects / 0 bytes in 109ms
10-28 10:18:20.555: DEBUG/dalvikvm(1804): GC_FOR_MALLOC freed 44 objects / 190080 bytes in 65ms
10-28 10:18:20.575: INFO/dalvikvm-heap(1804): Grow heap (frag case) to 3.721MB for 753680-byte allocation
10-28 10:18:20.675: DEBUG/dalvikvm(1804): GC_FOR_MALLOC freed 0 objects / 0 bytes in 95ms
10-28 10:18:22.725: DEBUG/dalvikvm(1804): GC_FOR_MALLOC freed 3 objects / 376904 bytes in 66ms
10-28 10:18:23.145: INFO/dalvikvm-heap(1804): Grow heap (frag case) to 4.799MB for 1507344-byte allocation
10-28 10:18:23.245: DEBUG/dalvikvm(1804): GC_FOR_MALLOC freed 0 objects / 0 bytes in 95ms
10-28 10:18:25.415: WARN/ActivityManager(59): Launch timeout has expired, giving up wake lock!
10-28 10:18:26.205: WARN/ActivityManager(59): Activity idle timeout for HistoryRecord43ef1378 com.xxx.xxxe/.TabViewMain
10-28 10:18:27.995: DEBUG/dalvikvm(1804): GC_FOR_MALLOC freed 3 objects / 753736 bytes in 65ms
10-28 10:18:28.655: INFO/dalvikvm-heap(1804): Grow heap (frag case) to 6.956MB for 3014672-byte allocation
10-28 10:18:28.765: DEBUG/dalvikvm(1804): GC_FOR_MALLOC freed 0 objects / 0 bytes in 102ms
10-28 10:18:33.275: DEBUG/dalvikvm(123): GC_EXPLICIT freed 833 objects / 48984 bytes in 2059ms
10-28 10:18:37.275: DEBUG/dalvikvm(1804): GC_FOR_MALLOC freed 3 objects / 1507400 bytes in 69ms
10-28 10:18:38.115: INFO/dalvikvm-heap(1804): Grow heap (frag case) to 11.268MB for 6029328-byte allocation
10-28 10:18:38.275: DEBUG/dalvikvm(1804): GC_FOR_MALLOC freed 0 objects / 0 bytes in 151ms
10-28 10:18:53.885: DEBUG/dalvikvm(1804): GC_FOR_MALLOC freed 3 objects / 3014728 bytes in 70ms
10-28 10:18:53.895: INFO/dalvikvm-heap(1804): Forcing collection of SoftReferences for 12058640-byte allocation
10-28 10:18:54.055: DEBUG/dalvikvm(1804): GC_FOR_MALLOC freed 0 objects / 0 bytes in 158ms
10-28 10:18:54.055: ERROR/dalvikvm-heap(1804): Out of memory on a 12058640-byte allocation.
编辑:好的,我可以让this example 工作,但即使有正确的权限,我也会收到权限被拒绝错误:
`10-2`8 11:33:15.478: WARN/System.err(1781): java.io.FileNotFoundException: /mnt/sdcard/testDirectory/Samples.zip (Permission denied)
【问题讨论】:
为什么要完全下载到内存中?我认为您对 java.io 不太熟悉。换句话说,您的问题不是针对 Android 的。 绝对是 Java 新手,仍在学习什么是什么。没有意识到 ByteArrayBuffer 正在被发送到 RAM,以为它正在被发送到 SD! 【参考方案1】:难怪,您正在尝试在手机的 RAM 中创建一个 22MB 字节数组;大多数安卓手机没有那么多内存。您要做的是将文件流式传输到 SD 卡或内部存储中:
// untested
final int BUFFER_SIZE = 23 * 1024;
InputStream is = ucon.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is, BUFFER_SIZE);
FileOutputStream fos = new FileOutputStream(file);
byte[] baf = new byte[BUFFER_SIZE];
int actual = 0;
while (actual != -1)
fos.write(baf, 0, actual)
actual = bis.read(baf, 0, BUFFER_SIZE);
fos.close();
【讨论】:
嗯...这给了我一个 java.io.file not found 异常(只读文件系统)。 @user375566:确保您的应用程序具有写入文件的适当权限developer.android.com/guide/topics/security/security.html,您应该决定是内部存储还是外部存储developer.android.com/guide/topics/data/data-storage.html 我正在使用外部,我认为我拥有所有必要的权限。这是一种下载大文件的小方法,受 Lie Ryan(感谢他)启发,使用 FileOutputStream
刷新缓冲区。
public void DownloadFromUrl(String fileURL, String fileName) //this is the downloader method
try
URL url = new URL( fileURL);
File file = new File(fileName);
file.createNewFile();
long startTime = System.currentTimeMillis();
Log.d("DownloadManager", "download begining");
Log.d("DownloadManager", "download url:" + url);
Log.d("DownloadManager", "downloaded file name:" + fileName);
/* Open a connection to that URL. */
URLConnection ucon = url.openConnection();
/*
* Define InputStreams to read from the URLConnection.
*/
InputStream is = ucon.getInputStream();
/*
* Read bytes to the Buffer until there is nothing more to read(-1) and write on the fly in the file.
*/
FileOutputStream fos = new FileOutputStream(file);
final int BUFFER_SIZE = 23 * 1024;
BufferedInputStream bis = new BufferedInputStream(is, BUFFER_SIZE);
byte[] baf = new byte[BUFFER_SIZE];
int actual = 0;
while (actual != -1)
fos.write(baf, 0, actual);
actual = bis.read(baf, 0, BUFFER_SIZE);
fos.close();
Log.d("DownloadManager", "download ready in"
+ ((System.currentTimeMillis() - startTime) / 1000)
+ " sec");
catch (IOException e)
Log.d("DownloadManager", "Error: " + e);
【讨论】:
【参考方案3】:为什么要使用 ByteArrayBuffer ?这就是问题所在,您试图在其中存储 22mb。
【讨论】:
以上是关于Android下载文件内存不足的问题的主要内容,如果未能解决你的问题,请参考以下文章
Azure SDK for php blob 下载导致内存不足