2013-10-24 34 views
0

考慮以下方法:Java中的多線程垃圾回收:外部共享對象阻止GC?

public void Parse(String[] S, Objects[] O) throws IOException { 
    final int N_THREADS = Runtime.getRuntime().availableProcessors(); 
    BlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<Runnable>(20); 
    RejectedExecutionHandler rejectedExecutionHandler = new ThreadPoolExecutor.CallerRunsPolicy(); 
    ThreadPoolExecutor service = new ThreadPoolExecutor(N_THREADS, N_THREADS, 0L, TimeUnit.MILLISECONDS, blockingQueue, rejectedExecutionHandler); 
    final SomeObject RO = new SomeObject(); 
    for(String s : S){ 
     service.execute(new Runnable() { 
      public void run() { 
       // initialize variables 
       for (Object o : O) { 
         V ps = RO.apply(sentence); 
         //more work on ps 
       } 
       File f = new File("something"); 
       FileWriter fw = null; 
       try { 
        fw = new FileWriter(f.getAbsoluteFile()); 
        BufferedWriter bw = new BufferedWriter(fw); 
       } catch (IOException e) { 
        System.out.println(f.getAbsoluteFile()); 
       } 
       BufferedWriter bw = new BufferedWriter(fw); 
       for (SentenceAnnotation entry : annotations) { 
        try { 
         bw.write(entry.toString()); 
         bw.newLine(); 
        } catch (IOException e) { 
         e.printStackTrace(); 
        } 
       } 

       try { 
        bw.flush(); 
        bw.close(); 
        fw.close(); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
      } 
     }); 
    } 
    service.shutdown(); 
    while (!service.isTerminated()) { 
    } 
    long timeEnd = System.currentTimeMillis(); 
} 

其中S是一個大陣列(幾十萬)和O是說長度50.我的問題是關於RO對象。它是在外部創建的,如果您願意,可以在所有主題中「共享」。現在,當這段代碼運行一段時間後,堆空間耗盡了,這讓我感到困惑。我傾向於認爲RO對象仍然保持其他已完成的Runnables存活並慢慢消耗內存。真的嗎?我使用`free -m'監視了linux系統(最新版本的Oracle JDK)的內存消耗,我可以慢慢但肯定地看到內存消失。我很感激你能給我的任何建議。

回答

1
try { 
    fw = new FileWriter(f.getAbsoluteFile()); 
    BufferedWriter bw = new BufferedWriter(fw); 
} catch (IOException e) { 
    System.out.println(f.getAbsoluteFile()); 
} 
BufferedWriter bw = new BufferedWriter(fw); 

您在本節代碼中泄漏未封閉的BufferedWriter。您創建try子句的第一個範圍,並且不要關閉它。引用消失,但運行時創建的任何本地句柄都不會被釋放。您沒有注意到,因爲之後立即爲同一個文件創建了一個新的BufferedWriter

0

就我所見,在你展示的代碼中沒有任何可疑的東西。

你最好的選擇是獲得應用程序的堆轉儲,然後檢查什麼是填充你的內存。

您可以生成堆轉儲並使用JVisualVM對其執行基本分析,該文件包含在您jdk的bin文件夾中。您肯定會在堆分析中找到許多有關SO的問題,例如How to find a Java Memory Leak

0

您似乎在創建兩次BufferedWriter。我不太確定這裏的範圍問題,但在我看來,這甚至不應該正確編譯。嘗試「試試看」的塊之前宣佈的BufferedWriter和簡單地使用它,而二度創作:

 BufferedWriter bw;    
     try { 
      fw = new FileWriter(f.getAbsoluteFile()); 
      bw = new BufferedWriter(fw); 
     } catch (IOException e) { 
      System.out.println(f.getAbsoluteFile()); 
     } 
     for (SentenceAnnotation entry : annotations) { 
      try { 
       bw.write(entry.toString()); 
       bw.newLine(); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     } 

如果我是正確的,那麼你就不會產生「十萬」不必要的BufferedWriter對象。雖然沒有保證。

作爲一個風格問題,我會考慮將「try」塊合併爲一個,並使用一個「catch」而不是兩個....除非您打算給出不同的錯誤消息,當然。

希望有所幫助。

Achim