从Java中的大文件读取字节会导致Java堆空间错误

从Java中的大文件读取字节会导致Java堆空间错误,java,bytearray,inputstream,out-of-memory,outputstream,Java,Bytearray,Inputstream,Out Of Memory,Outputstream,不久前,我正在寻求以下代码方面的帮助,并最终再次开始工作。基本上,我已将错误缩小到导致此错误的文件大小: 线程“main”java.lang.OutOfMemoryError中出现异常:java堆空间 堆栈跟踪中该错误正下方的行是: 位于java.util.Arrays.copyOf(Arrays.java:2786) 我可以向这个程序传递一个包含数千个较小文件的大目录,但是任何超过50MB大小的文件都会崩溃。我没有追踪程序崩溃的确切大小,但我知道至少50 Mb的文件会导致问题 下面是主要代码段

不久前,我正在寻求以下代码方面的帮助,并最终再次开始工作。基本上,我已将错误缩小到导致此错误的文件大小:

线程“main”java.lang.OutOfMemoryError中出现异常:java堆空间

堆栈跟踪中该错误正下方的行是: 位于java.util.Arrays.copyOf(Arrays.java:2786)

我可以向这个程序传递一个包含数千个较小文件的大目录,但是任何超过50MB大小的文件都会崩溃。我没有追踪程序崩溃的确切大小,但我知道至少50 Mb的文件会导致问题

下面是主要代码段,堆栈跟踪告诉我的代码正在中断

private void handleFile(File source)
{
    FileInputStream fis = null;

    try
    {
        if(source.isFile())
        {
            fis = new FileInputStream(source);
            handleFile(source.getAbsolutePath(), fis);
        }
        else if(source.isDirectory())
        {
            for(File file:source.listFiles())
            {
               if(file.isFile())
               {
                   fis = new FileInputStream(file);
                   handleFile(file, fis);
               }
               else
               {
                   handleFile(file);
               }
            }
         }
     }
     catch(IOException ioe)
     {
         ioe.printStackTrace();
     }
     finally
     {
         try
         {
             if(fis != null) { fis.close(); }
         }
         catch(IOException ioe) { ioe.printStackTrace(); }
     }
}

private handleFile(String fileName, InputStream inputStream)
{
    byte[] startingBytes = null;

    try
    {
       startingBytes = inputStreamToByteArray(inputStream);

       if(startingBytes.length == 0) return;

       if(isBytesTypeB(startingBytes))
       {
          do stuff
          return;
       }
     }
     catch(IOException ioe)
     {
         ioe.printStackTrace();
     }
}

private byte[] inputStreamToByteArray(InputStream inputStream)
{
    BufferedInputStream bis = null;
    ByteArrayOutputStream baos = null;

    try
    {
        bis = new BufferedInputStream(inputStream);
        baos = new ByteArrayOutputStream(bis);

        byte[] buffer = new byte[1024];

        int nRead;
        while((nRead = bis.read(buffer)) != -1)
        {
            baos.write(buffer, 0, nRead);
        }
    }
    finally { baos.close(); }

    return baos.toByteArray();
 }

 private boolean isBytesTypeB(byte[] fileBytes)
 {
     // Checks if these bytes match a particular type
     if(BytesMatcher.matches(fileBytes, fileBytes.length))
     {
         return true;
     }
     return false;
 }

因此,上面的代码中有一些东西导致了错误。你知道我做错了什么吗?

我还没有读过你所有的代码,但是可以用更多的堆空间启动Java

java -Xmx128m

例如。

我还没有阅读您的所有代码,但是可以使用更多可用堆空间启动Java

java -Xmx128m


例如。

数组。每当需要调整
ByteArrayOutputStream的内部数组的大小时,都会调用copyOf
。这是内存需求最高的时刻。通过将数组的初始大小指定为文件大小,可以避免调整数组大小。

数组。每次需要调整
ByteArrayOutputStream的内部数组大小时,都会调用copyOf
。这是内存需求最高的时刻。通过将数组的初始大小指定为文件大小,可以避免调整数组大小。

您可以从Windows>Preferences>Java>Installed JRE中增加堆空间,从中选择JRE并单击edit,然后写入默认VM参数:to-Xmx2048(它将分配2gb)

您可以从Windows>Preferences>Java>Installed JRE中增加堆空间,从中选择JRE并单击edit,然后写入默认VM参数:to-Xmx2048(它将分配2gb)

一个解决方法是在运行应用程序时增加堆内存。不过,如果你只是复制一个文件,为什么你必须把整个文件都保存在RAM中?我的程序需要把文件放在RAM中,因为它最终会用读取的字节做一些事情。为什么不把它们分块处理呢?如果你指定了真正的问题,你可以得到一个真正的答案,而不是解决办法。我不完全理解你的评论?据我所知,真正的问题是,在我的程序还没来得及处理我读入的字节之前,大文件的内存就用完了。问题是:为什么需要将整个文件放在RAM中?真的有必要吗?既然您只是在使用其中的字节(至少在您的示例中是这样),为什么不使用小块的
byte[]
来处理它们,而不是处理来自文件的整个
byte[]
?一种解决方法是在运行应用程序时增加堆内存。不过,如果你只是复制一个文件,为什么你必须把整个文件都保存在RAM中?我的程序需要把文件放在RAM中,因为它最终会用读取的字节做一些事情。为什么不把它们分块处理呢?如果你指定了真正的问题,你可以得到一个真正的答案,而不是解决办法。我不完全理解你的评论?据我所知,真正的问题是,在我的程序还没来得及处理我读入的字节之前,大文件的内存就用完了。问题是:为什么需要将整个文件放在RAM中?真的有必要吗?既然您只是使用其中的字节(至少从您的示例中),为什么不使用小块的
byte[]
来处理它们,而不是处理来自您文件的整个
byte[]
?因此您的建议是获取文件的大小,然后将该大小分配给字节数组的大小?是的,这是避免额外内存需求的唯一方法。您还可以考虑java NIO方法,例如内存映射文件,您可以像内存中数组那样访问这些文件。实际上,您将访问操作系统磁盘缓存的本机内存。是的,这是避免额外内存需求的唯一方法。您还可以考虑java NIO方法,例如内存映射文件,您可以像内存中数组那样访问这些文件。实际上,您将访问操作系统磁盘缓存的本机内存。我尝试按照您的建议在ByteArrayOutputStream的构造函数中指定文件大小,但仍然遇到相同的错误。我做得不对吗?ByteArrayOutputStream baos=新的ByteArrayOutputStream((int)文件大小);因此,您的建议是获取文件的大小,然后将该大小分配给字节数组的大小?是的,这是避免额外内存需求的唯一方法。您还可以考虑java NIO方法,例如内存映射文件,您可以像内存中数组那样访问这些文件。实际上,您将访问操作系统磁盘缓存的本机内存。是的,这是避免额外内存需求的唯一方法。您还可以考虑java NIO方法,例如内存映射文件,您可以像内存中数组那样访问这些文件。实际上,您将访问操作系统磁盘缓存的本机内存。我尝试按照您的建议在ByteArrayOutputStream的构造函数中指定文件大小,但仍然遇到相同的错误。我做得不对吗?ByteArrayOutputStream baos=新的ByteArrayOutputStream((int)文件大小);需要进行这种修改是常见的吗?是否是糟糕的编码导致我不得不以这种方式修改设置?我试图传递数据块,但我的一个方法需要所有字节才能正确操作数据。@StinePike。。很抱歉我在上面的评论中给你贴标签。我想如果你可以的话也没关系