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

时间:2013-05-08 17:33:20

标签: java bytearray inputstream out-of-memory outputstream

前一段时间我正在寻求下面代码的帮助,最后再次开始研究它。基本上,我已将我的错误缩小到导致此错误的文件大小:

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

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

我可以将这个程序传递给包含数千个较小文件的大型目录,但任何超过50 Mb大小的文件都会崩溃。我没有跟踪程序崩溃的确切大小,但我知道至少有一个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;
 }

因此上述代码中存在导致错误的内容。我在这里做错了什么想法?

3 个答案:

答案 0 :(得分:2)

每次Arrays.copyOf的内部数组需要调整大小时,都会调用

ByteArrayOutputStream。这是内存需求最高的时刻。您可以通过指定数组的初始大小等于文件大小来避免数组大小调整。

答案 1 :(得分:1)

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

java -Xmx128m

例如。

答案 2 :(得分:1)

您可以从Windows增加堆空间>偏好> Java和GT;从那里安装JRE选择JRE并单击编辑,然后写入默认VM参数:到-Xmx2048(它将分配2gb)