2013-12-17 139 views
4

我嘗試讀取超過400萬行,大小超過400 MB的日誌文件,但我得到內存不足錯誤:java堆空間。這是我的代碼:內存不足錯誤,Java堆空間

File file = new File("C:\\file.log"); 
     FileReader fileReader = new FileReader(file); 
     BufferedReader bufferedReader = new BufferedReader(fileReader); 
     StringBuilder stringBuffer = new StringBuilder(); 
     String line; 
     while ((line = bufferedReader.readLine()) != null) { 
      stringBuffer.append(line); 
     } 

我試圖增加堆內存到1GB,但仍然得到該消息。可能的原因是什麼?

+2

不要將整個文件存儲在一個StringBuffer中......你想用文件內容做什麼? –

+0

@ElliottFrisch如果他已經增加到1GB,文件只有400MB - 它會失敗嗎? –

+0

@ElliottFrisch:我試着用特定的參數分割它 –

回答

15

好的,你已經應該有線索,閱讀你得到的評論。

問題說明:

您的日誌文件大小爲400MB。請注意,這是以字節計量的。現在,您正在逐行閱讀line = bufferedReader.readLine(),從而將一些字節轉換爲字符串。

Java中的String實例內部擁有char[]。但是Java中的char需要2個字節!所以你至少需要800MB的堆空間來存儲所有的字符。由於您還在分配其他幾個對象,並且JVM本身需要一些內存,所以很可能1 GB是不夠的。

此外,StringBuffer(順便說一下:更好地使用StringBuilder)內部再次使用char[],它在需要時自動擴展(長度)。這種擴展是通過加倍長度來完成的。所以對於一個400MB的文件,它有一個char[],長度爲512M。仍然提醒:一個字符需要2個字節。

那麼解決方案是什麼?簡單地說:不要將整個文件讀入內存!

做的是不是:

class LogAnalyzer { 
    private final File logFile; 

    LogAnalyzer(File logFile) { 
     this.logFile = logFile; 
    } 

    void analyze() throws IOException { 
     try(FileReader fileReader = new FileReader(logFile)) { 
      try(BufferedReader bufferedReader = new BufferedReader(fileReader)) { 
       String line; 
       while ((line = bufferedReader.readLine()) != null) { 
        analyzeLine(line); 
       } 
      } 
     } 
    } 

    private void analyzeLine(String line) { 
     // do whatever you need here 
    } 
} 

如果你需要保留一些行,你應該把它們存儲在紀錄分析工具的一些實例字段,和/或擁有此類行爲像一個狀態機。