2012-05-18 86 views
0

我試圖遞歸遍歷我的雲端硬盤來搜索一些文件。 當有限的文件夾/文件時,代碼工作正常,但是當我將搜索目標定位到C驅動器時,我在其中有大量文件將其從堆內存中拋出。如何管理Java中的堆空間

異常的線程「主題-4」 java.lang.OutOfMemoryError:Java堆空間

  1. 請建議我一些好的內存管理技巧尤其是當我們做遞歸調用。
  2. 或者給我更好的方法來遍歷目錄沒有遞歸。

我不想增加最大允許的堆空間,因爲它就像暫緩推遲問題一樣。

代碼:

void iterateDirectory(String somedir) { 


     File dir = new File(somedir); 
     File[] files = dir.listFiles(); 
     if (files != null) { 
      for (int id = 0; id < files.length; id++) { 
       if (files[id].isDirectory() == false) 
       { 
        fsTree.add(files[id].toString()); // taking list of files 
       } 
       else 
       { 
        iterateFilesInDirectory(files[id].getAbsolutePath()); 
       } 
      } 
     } 
    } 
+2

@JeremyHeiler這很可能會令事情更糟糕,錯誤表示它的堆空間不足,而不是堆棧空間。 – Dunes

+2

您究竟如何遞歸?目錄結構是一個「樹」,所以搜索通常是樹的深度優先或寬度優先遍歷。 – ArjunShankar

+0

如果你做得對,深度優先的100級樹遍歷仍然只有100個節點在任何時間點佔用內存。 – ArjunShankar

回答

-1

有限制爲能做什麼遞歸,即相對於棧/堆使用。請記住,無論您可以遞歸執行,您都可以迭代執行;改寫你的代碼來代替使用迭代解決方案。

替代解決方案:在java.nio中有一個接口,可用於遞歸地遍歷文件系統的結構。看看this trailSimpleFileVisitor

+1

您的解決方案緩解堆內存不足就是從堆棧中刪除內存(用於存儲正在探索的樹和其上的位置)並將其移至堆中。不知道我遵循你的推理。 – Dunes

+0

@Dunes:我不記得暗示這一點。在最小的情況下,堆棧不會因過多的調用而負擔過重,這是我的意圖。另一方面,堆意味着有很多對象被創建是不必要的。由於我們沒有代碼,我們不能假定發生的地方。 – Makoto

+2

我們足夠了解,遞歸不是問題,因爲錯誤是OutOfMemoryError而不是StackOverflowError。 – Dunes

1

有兩種可能性:

  1. 有一個在你的代碼無限遞歸(例如,因爲你不處理.和/或..正確)。如果是這樣的話,你必須修復代碼。
  2. 您的代碼真正需要比可用的更多的堆空間。你有兩種選擇:
    • 減少你的進程的內存需求(一個內存分析器可以幫助你理解什麼在使用所有的堆空間);
    • 通過指定-Xmx JVM選項來增加堆大小。
+0

它不能是'1',因爲OP已經聲明代碼適用於較小的示例。 – ArjunShankar

2

的罪魁禍首,因爲我看到它是這一行:

fsTree.add(files[id].toString()); // taking list of files 

看來,你添加每一個文件到全局數據結構(fsTree),然後搜索有。

我的選擇是:

A.它不會,如果你「轉換」你的遞歸函數成一個迭代走開。

B.它去,而不是追加到一個全局數據結構,並最終搜索的路程,如果,你做搜索/本地匹配,只有在全球範圍緩存匹配的命中:

void iterateDirectory (String somedir, String search_term) { 

    File dir = new File(somedir); 
    File[] files = dir.listFiles(); 
    if (files != null) { 
     for (int id = 0; id < files.length; id++) { 
      if (files[id].isDirectory() == false) 
      { 
       if (/* files[id].isDirectory() MATCHES search_term */) 
       // add to list of matching files: 
       matching_hits.add(files[id].toString()); 
      } 
      else 
      { 
       iterateFilesInDirectory(files[id].getAbsolutePath()); 
      } 
     } 
    } 
}