这两天发现项目中有个模块有内存泄露,512 MB的堆内存大概在5个小时左右被耗尽。通过NB的profiler跟踪可以看到如下结果: profiler java.util.concurrent.LinkedBlockingQueue.Node对象尽然占了一多半。在实时profile中发现即使限定了list的capacity并且在不断调用take方法(相当于remove)时,Node的alive object数量仍在不断增长(照理说在某个时间节点后alive object数量应该增长得很缓慢,因为take的Node对象会被GC)。将LinkedBlockingQueue换成ArrayBlockingQueue后问题解决。继而发现LinkedList有同样的问题,于是得出结论:

  1. LinkedXxxx集合的remove、take,甚至clear方法不会导致被挪出队列的node马上被标记为可GC,可能会经过一个很长的时间(generation数量相当大)
  2. 由1推测LinkedXxxx的实现可能有内存泄露,或者JVM的GC算法可能有缺陷
  3. 由1、2得出经验:在集合内容需要做频繁替换(不断add/remove或者put/take)且程序运行时间很长的情况下最好不要使用LinkedXxxx,应该用ArrayXxxx替代并且指定capacity

补:感谢blader的补充,这个问题果然是个bug:http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6460501