2013-10-24 30 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