回忆一下:1年前在做断点续传因粗心编码导致的内存溢出问题。当时在做分片时,当分片容量大于512M时,内存溢出,抛出异常:java.lang.OutOfMemoryError: Java heap space。

分析一下:当时虚拟机堆内存正好设置为512M,当申请堆空间大于该值时出现如上异常。

今日重写代码测试,讲解出错的原因以及解决方案。

public static void testOutMemory() throws IOException {
		//绝对路径
		String inPath = "D:/TestFile/in/bigFileTest.zip";
		String outPath = "D:/TestFile/out/bigFileTest.zip";
		File inFile = new File(inPath);
		File outFile = new File(outPath);
		if (!inFile.exists()) {
			//TODO 文件不存在
		long fileLength = inFile.length();//文件大小,我的测试值为: 1820595407
		ByteArrayOutputStream bos = new ByteArrayOutputStream((int) fileLength);//这一行会抛出异常
		BufferedInputStream in = new BufferedInputStream(new FileInputStream(inFile));
		FileOutputStream fileOutputStream = new FileOutputStream(outFile);
		int buf_size = 1024;
		byte[] buffer = new byte[buf_size];
		int len = 0;
		while (-1 != (len = in.read(buffer, 0, buf_size))) {
			bos.write(buffer, 0, len);
		byte[] data = bos.toByteArray();
		fileOutputStream.write(data);
		fileOutputStream.flush();
		fileOutputStream.close();
        bos.close();
		System.out.println("测试完成");

执行方法,在ByteArrayOutputStream bos = new ByteArrayOutputStream((int) fileLength);这一行会抛出异常,查看ByteArrayOutputStream构造方法,其中有一句为buf = new byte[size], 也正是在这一句抛出的异常,问题已经找到。

难道需要通过增加堆内存的方式来解决这个问题?当然不是。虽然可以暂时解决问题,但依然会埋下一枚地雷,当下一文件更大时,这个问题将会重新出现。

废话不多说,在代码中用一次缓存较大数据本身就不可取,上面的代码实现的文件传输本就不应该先把文件存放到内存,再将内存中的数据传输到其他位置,很明显这是一次很垃圾的编码。于是,优化如下:

public void testOutMemory() throws IOException {
		// 绝对路径
		String inPath = "D:/TestFile/in/bigFileTest.zip";
		String outPath = "D:/TestFile/out/bigFileTest.zip";
		File inFile = new File(inPath);
		File outFile = new File(outPath);
		if (!inFile.exists()) {
			// TODO 文件不存在
		BufferedInputStream in = new BufferedInputStream(new FileInputStream(inFile));
		FileOutputStream fileOutputStream = new FileOutputStream(outFile);
		int buf_size = 1024;
		byte[] buffer = new byte[buf_size];
		int len = 0;
		while (-1 != (len = in.read(buffer, 0, buf_size))) {
			fileOutputStream.write(buffer, 0, len);//一次仅传输1K,不会溢出
		fileOutputStream.flush();
		fileOutputStream.close();
		System.out.println("测试完成");

(PS:我的堆内存为2G,文件大小约1.7G,为什么会内存溢出了,在这篇文章中会进行详细探索)。

回复里面好像不参添加图片,为了说明这段代码不会出现OOM,刚才亲测文件下载,大约5个G,@我问佛陀 请见:

private void download(String downloadUrl, String path){ InputStream inputStream = null; OutputStream outputStream = null; try { 两周前就想把这点经验记录下来了,由于拖延症上身,直到刚才突然想起这件未完成的任务,今天是1024,在这个特别的日子里,祝所有程序猿兄弟姐妹们节日快乐! 上传功能一直很正常,直到上传了个500多兆的文件,报错提示: “System.OutOfMemoryException”类型的异常在 mscorlib.dll 中发生,但未在用户代码中进行处理 对于内部用途和新的托管对象,确保要有足够的内存可... 今天一同事做了批量导入数据的功能,但是服务器老是死机。查看服务器内存8G的内存占了7G多,很明显是内存泄漏。后来发现对文件的操作的候用到了ByteArrayInputStream,仔细查看代码看到了ByteArrayInputStream并没有释放,问题差不多就是这个了,然后想着关闭流,自然的想到了ByteArrayInputStream.close()方法。后经网络查证,close方法在Byt ByteArrayOutputStream baos = makePdfByJson(result.toString(), “”); if (baos.size() > 0) { txtFilePath.setText(filePath.toString()); 每次我上传带有部分数据的excel,上传的文件都会损坏,并且我无法在aspose工作簿中使用此上传的文件(在某些情况下它也可以工作,我不知道为什么)。 甚至在我打开的同,excel也会显示损坏的文件消息。 这是片段InputStream stream = file.getInputStream();OutputStream os = new FileOutputStream("path_t... 上一篇Android开发——常见的内存泄漏以及解决方案(一)中已经对部分可能会引发内存泄漏的情况进行了阐述,此篇将从图片、动画等资源角度介绍可能会造成内存泄漏的情况以及应对方法。6. 集合类导致内存泄漏很常见的一个例子就是图片的三级缓存结构,为了更好的用户体验,缓存机制必不可少,三级缓存分别为网络缓存,本地缓存以及内存缓存。... 1、java.lang.OutOfMemoryError: PermGen space JVM管理两种类型的内存,和非是给开发人员用的上面说的就是,是在JVM启动创建;非是留给JVM自己用的,用来存放类的信息的。它和不同,运行期内GC不会释放空间。如果web app用了大量的第三方jar或者应用有太多的class文件而恰好MaxPermSize设置较小,超出了也... 一、Maven编译过程中出现java.lang.OutOfMemoryError: Java heap space 错误,提示如下:                java.lang.OutOfMemoryError: Java heap space                  at java.util.Arrays.copyOf(Arrays.java:2786)