2012-04-14 46 views
-1

這裏是有罪代碼:一個的bizzare的Java IO失敗,說明

// Demo the java.lang.OutOfMemoryError: Java heap space error. 

    import java.util.*; 

    public class Bozo { 

     void TstReadFile() { 
     SubBozo sb = new SubBozo(); 
     sb.readFile(); 
     } 

    public static void main(String[] args) { 
     Bozo b = new Bozo(); 
     b.TstReadFile(); 
    } 
    } 


/** Read in the observing list file. */ 

import java.io.*; 
import java.util.*; 

public class SubBozo { 

    public boolean readFile() { 

    int lineCt = 0;   // Count the lines read in observingList. 

    long heap, 
     heapMaxSize, 
     heapFreeSize; 

    String s = "Unstarted"; 

    FileInputStream fis = null; 
    DataInputStream in = null; 
    BufferedReader br = null; 

    try { 
     fis = new FileInputStream("../data/observingList"); 
     in = new DataInputStream(fis); 
     br = new BufferedReader(new InputStreamReader(in)); 
    } catch (Exception e) { 
     System.out.println("Couldn't open ../data/observingList because " + 
         e.getMessage()); 
    } 

    boolean go = true; 
    while (go) { 
     try { 
     s = br.readLine(); // Lines should not be longer than say 256 characters. 
     } catch (Exception e) { 
     System.out.println("Couldn't read ../data/observingList because " + 
          e.getMessage()); 
     heap = Runtime.getRuntime().totalMemory(); 
     heapMaxSize = Runtime.getRuntime().maxMemory(); 
     heapFreeSize = Runtime.getRuntime().freeMemory(); 
     System.out.println("" + lineCt + ") " + "Total Memory (MB): " + 
          (heap/1048576) + "\n Heap Max Size (MB): " + 
          (heapMaxSize/1048576) + 
          "\n Heap Free Size (MB): " + 
          (heapFreeSize/1048576)); 
     go = false; 
     } 

     if ((lineCt++ % 1000) == 0) { 
     System.gc(); 
     heap = Runtime.getRuntime().totalMemory(); 
     heapMaxSize = Runtime.getRuntime().maxMemory(); 
     heapFreeSize = Runtime.getRuntime().freeMemory(); 
     System.out.println("" + lineCt + ") " + "Total Memory (MB): " + 
          (heap/1048576) + "\n Heap Max Size (MB): " + 
          (heapMaxSize/1048576) + 
          "\n Heap Free Size (MB): " + 
          (heapFreeSize/1048576)); 
     } 
    } 

    try { 
     br.close(); 
     in.close(); 
     fis.close(); 
    } catch (Exception e) { 
     System.out.println("Couldn't close the input file stream because " + 
         e.getMessage()); 
    } 
    return true; 
    } 
} 

當這個運行時,使用以下命令:

星雲:finderChart/src目錄的java博佐

它拋出了的內存錯誤。這裏的打印輸出:

1)的總內存(MB):119 堆最大大小(MB):1776 堆免費大小(MB):118

1001)的總內存(MB):119 堆最大大小(MB):1776 堆免費大小(MB):119

2001)的總內存(MB):119 堆最大大小(MB):1776 堆免費大小(MB):119

3001)總內存(MB):119 堆最大大小(MB):1776 堆免費大小(MB):119

異常線程 「main」 java.lang.OutOfMemoryError:在java.util.Arrays.copyOf Java堆空間 (Arrays.java:2882 ) 在java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:100) 在java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:515) 在java.lang.StringBuffer.append(StringBuffer.java:306) 在java.io.BufferedReader.readLine(BufferedReader.java:345) 在java.io.BufferedReader.readLine(BufferedReader.java:362) 在SubBozo.readFile(SubBozo.java:34) 在Bozo.TstReadFile(博若.java:10)(Bozo.java:15)

現在爲bizzare部分,但我懷疑你已經看到了它。 JVM每隔1000行輸出其內存使用量。它沒有耗盡內存。

當拋出的錯誤,錯過了追趕:

嘗試{

s = br.readLine(); 

}趕上(例外五){

System.out.println("Couldn't read ../data/observingList because " 
... 

}

所以讓我們嘗試增加內存: 的java -Xmx1024m博若

同樣的結果,所以我就不再重複了。

發生了什麼事是,文件中讀取,obasrvingList,有一些非常長(> 2048字節)在它行。這嚇壞了Java,但直到我試圖在Vim中編輯文件並發現vim無法編輯它時,才發現很明顯,對於文本閱讀器來說,瘋狂的長線條是一個問題。

TIA

湯姆

+4

這是......徹底的,但是......你的問題是什麼? – 2012-04-14 19:38:32

+1

'OutOfMemoryError'不是一個例外:'OutOfMemoryError擴展VirtualMachineError擴展Error extends Throwable extends Object'。 – trutheality 2012-04-14 19:44:56

回答

1

BufferredReader.readLine回報null如果沒有數據,它不拋出異常。因此,將您的代碼更改爲:

while (go) { 
    s = br.readLine(); 
    if (s = null) break; 

而不是處理異常。這就是爲什麼你的代碼永遠不會離開週期,並可能無限地分配內存。

3

你沒有問任何問題,但這裏有一些答案:

When the error is thrown, it misses the catch:

因爲你正趕上ExceptionOutOfMemoryError沒有擴展它。感謝上帝,因爲你忽略了堆棧跟蹤在登錄異常:

System.out.println("Couldn't read ../data/observingList because " + 
         e.getMessage()); 

而是始終使用:

e.printStackTrace(); 

更好 - 使用一些日誌框架。

It's not runing out of memory.

嗯,是的。它試圖分配一個太大的數組(例如:你有50個免費的MiB,並試圖分配60個MiB)。這就是StringBuffer的工作方式 - 將內部陣列的大小加倍,同時保留舊的和新的參考。

What happened is that the file being read, obasrvingList, had some very long (> 2048 bytes) lines in it. This freaked out Java, but it wasn't until I tried to edit the file in Vim

我可以向你保證2048個字符對於JVM來說沒有任何意義。我懷疑問題行至少有幾百萬字符...即使未能打開該文件(可能是最優化的編輯器),所以行可能非常長。

此外,我對整體代碼質量有一些建議(如吞嚥異常並返回false,go布爾標誌控制循環) - 但這更適合於http://codereview.stackexchange.com

+0

原來這裏分別是幾百萬字符。我以前從來沒有遇到過一個問題,堆棧跟蹤沒有在嚴重錯誤上打印,因此我沒有明確包含它們。感謝您的分析!直到你提到它,我認爲Exception是所有例外的一個catchall! – Boffin 2012-04-14 20:55:49