java.lang.OutOfMemoryError:从URL下载大文件时的java堆空间

java.lang.OutOfMemoryError:从URL下载大文件时的java堆空间,java,out-of-memory,download,Java,Out Of Memory,Download,我想从URL下载一个文件。文件大小为564.31MB。我不知道这里发生了什么错误。另外,我想知道我的代码是否是从URL下载文件的正确方法。如果有更好的方法,请详细告诉我为什么比这更好。谢谢 import org.apache.commons.io.FilenameUtils; import java.io.*; import java.net.MalformedURLException; import java.net.URL; /** * Created by lukas on 6/30/

我想从URL下载一个文件。文件大小为564.31MB。我不知道这里发生了什么错误。另外,我想知道我的代码是否是从URL下载文件的正确方法。如果有更好的方法,请详细告诉我为什么比这更好。谢谢

import org.apache.commons.io.FilenameUtils;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;

/**
 * Created by lukas on 6/30/16.
 */
public class Main {
    public static void main(String[] args){
        try {
            String link = "https://s.basketbuild.com/uploads/devs/dianlujitao/oneplus3/cm13/cm-13.0-20160621-UNOFFICIAL-oneplus3.zip";
            URL url = new URL(link);
            InputStream inputStream = new BufferedInputStream(url.openStream());
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            int n=0;
            byte[] buf = new byte[1024];
            long duration = System.currentTimeMillis();
            while((n=inputStream.read(buf))!=-1){
                byteArrayOutputStream.write(buf, 0, n);
            }
            duration = System.currentTimeMillis()-duration;
            System.out.println("Finish in "+duration+"ms");

            inputStream.close();

            File dir = new File("Output path");
            if(!dir.exists())
                dir.mkdirs();

            String fileBaseName = FilenameUtils.getBaseName(link);
            String fileExtension = FilenameUtils.getExtension(link);
            System.out.println("Name: "+fileBaseName+'.'+fileExtension);
            File outputFile = new File(dir, fileBaseName+'.'+fileExtension);

            if(!outputFile.exists()){
                outputFile.createNewFile();
            }

            FileOutputStream fileOutputStream = new FileOutputStream(outputFile);
            fileOutputStream.write(byteArrayOutputStream.toByteArray());

            //release outputstream
            byteArrayOutputStream.close();
            fileOutputStream.close();

            System.out.println("Your download has been finished");


        } catch (MalformedURLException e) {
            e.printStackTrace();
            System.out.println("Something unexpected has happened!");
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("Something unexpected has happened!");
        }


    }
}
下面是我的控制台所说的:

Finish in 133506ms
Name: cm-13.0-20160621-UNOFFICIAL-oneplus3.zip
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Arrays.java:3236)
    at java.io.ByteArrayOutputStream.toByteArray(ByteArrayOutputStream.java:191)
    at Main.main(Main.java:42)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
  • ByteArrayOutputStream在堆内存中分配其所有数据。正确的方法是直接写入文件,并为此使用缓冲区,以便优化磁盘I/O:

    OutputStream os = new BufferedOutputStream(new FileOutputStream("myFile.txt")); OutputStream os=new BufferedOutputStream(新文件OutputStream(“myFile.txt”))
  • System.currentTimeMillis()提供当前日期和时间,这些日期和时间在任何时候都可能更改。它不是用来计算持续时间的,请使用SystemClock.nanoTime()进行计算

  • ByteArrayOutputStream在堆内存中分配其所有数据。正确的方法是直接写入文件,并为此使用缓冲区,以便优化磁盘I/O:

    OutputStream os = new BufferedOutputStream(new FileOutputStream("myFile.txt")); OutputStream os=new BufferedOutputStream(新文件OutputStream(“myFile.txt”))
  • System.currentTimeMillis()提供当前日期和时间,这些日期和时间在任何时候都可能更改。它不是用来计算持续时间的,请使用SystemClock.nanoTime()进行计算


  • 欢迎访问SO的可能副本。在花时间写问题之前寻找可能的答案是个好主意。通常只要用谷歌搜索主错误消息就可以了(在本例中是
    java.lang.OutOfMemoryError:java heap space
    )。最好把它们分开。通常,“如何做得更好”的问题不会得到很多答案,因为这不是我们来这里的目的。请阅读和。为什么不直接写入
    FileOutputStream
    ,而不是
    ByteArrayOutputStream
    ?这样,您就可以下载100GB的文件,而不会耗尽内存此外,您不需要调用
    createNewFile()
    。欢迎使用SO的可能重复项。在花时间写问题之前寻找可能的答案是个好主意。通常只要用谷歌搜索主错误消息就可以了(在本例中是
    java.lang.OutOfMemoryError:java heap space
    )。最好把它们分开。通常,“如何做得更好”的问题不会得到很多答案,因为这不是我们来这里的目的。请阅读和。为什么不直接写入
    FileOutputStream
    ,而不是
    ByteArrayOutputStream
    ?这样,您就可以下载100GB的文件,而不会耗尽内存另外,您不需要调用
    createNewFile()
    。这里不要使用
    BufferedOutputStream
    。分配一个固定大小的缓冲区,并用它读写数据块。@erickson这就是BufferedOutputStream的确切功能。您的方法不能保证数据块已满,从网络上读取数据甚至可以一次返回一个字节。未缓冲的磁盘I/O是多余的。不需要保证区块已满。下载文件时的单字节网络读取是病态的。多余的复制太过分了。我认为这是一种观点。使用一个额外的8192字节的RAM缓冲,当它满时,会同步写入磁盘,这比写入未知的N字节要快得多(其中0BufferedOutputStream。分配一个固定大小的缓冲区,并用它读写数据块。@erickson BufferedOutputStream就是这样做的。你的方法不能保证数据块是满的,从网络上读取数据甚至可以一次返回一个字节。未缓冲的磁盘I/O过多l、 无需保证数据块已满。下载文件时单字节网络读取将是病态的。冗余复制是多余的。我认为这是一种观点。使用额外的8192字节RAM缓冲,当数据块已满时,将同步写入磁盘,比写入未知的N字节(其中0