2013-05-08 67 views
0

前一段時間,我在尋求下面的代碼的幫助,並最終開始再次處理它。基本上,我已經收窄我的錯誤下來的文件導致此錯誤大小:從Java中的大文件中讀取字節會導致Java堆空間錯誤

異常線程「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; 
} 

所以在上面的代碼中有一些導致錯誤。任何想法我在這裏做錯了嗎?

+0

一種解決方法在運行應用程序時會增加堆內存。但是,如果你只是複製一個文件,爲什麼你必須將整個文件保存在RAM中? – 2013-05-08 17:37:34

+0

我的程序需要RAM中的文件,因爲它最終會對讀取的字節做些什麼。 – 2013-05-08 17:38:56

+0

爲什麼不只是將它們處理成塊?如果你指定了真正的問題,你可以得到一個真正的答案,而不是解決方法。 – 2013-05-08 17:39:29

回答

2

Arrays.copyOf每次調用ByteArrayOutputStream的內部數組需要調整大小。這是最高內存需求的時刻。您可以通過指定數組的初始大小等於文件大小來避免數組大小調整。

+0

所以你的建議是獲取文件的大小,然後將該大小分配給字節數組的大小? – 2013-05-08 17:42:23

+1

是的,這是避免額外內存需求的唯一方法。您還可以考慮Java NIO方法,例如內存映射文件,您可以像內存數組一樣訪問它。您將實際訪問操作系統磁盤緩存的本機內存。 – 2013-05-08 17:51:53

+0

是的,這是避免額外內存需求的唯一方法。您還可以考慮Java NIO方法,例如內存映射文件,您可以像內存數組一樣訪問它。您將實際訪問操作系統磁盤緩存的本機內存。 – 2013-05-08 17:52:09

1

我沒有看到所有的代碼,但有可能與現有

java -Xmx128m 

例如更多的堆空間啓動Java。

1

可以增加從Windows>首選項> Java的堆的空間>從那裏安裝的JRE選擇JRE並單擊編輯,然後寫在默認VM參數:要-Xmx2048(它將分配2GB)

+0

需要進行此修改是否很常見?這可能是糟糕的編碼,導致我不得不以這種方式修改我的設置?我嘗試傳遞我的數據塊,但我的方法之一需要所有的字節正確操作數據。 – 2013-05-09 13:13:37

+0

@StinePike ..很抱歉在我上面的評論中標記了你。 – 2013-05-09 14:46:08

+1

我認爲如果你能弄清楚什麼是你的最大限度是可以的。但是,這不會給你無限的內存。所以對於一些明顯的情況,如果你的應用需要分配更多的內存,那麼你可以按照這個 – stinepike 2013-05-09 14:54:35