2013-03-26 1 views
3

В настоящее время я изучаю утечку памяти в одном из наших приложений. После дальнейшего расследования я придумал тест двух простых приложений для Java-качания, которые простаивают почти 14 часов. Оба приложения состоят из 30 JButtons.Idle Simple Java Swing Application Memory Leaks

1-приложение использует сильную ссылку для его действий слушателя:

jButton1.addActionListener(new java.awt.event.ActionListener() { 
    public void actionPerformed(java.awt.event.ActionEvent evt) { 
      jButton1ActionPerformed(evt); 
    } 
}); 

2-е приложение использует слабую ссылку для его действий слушателя:

jButton1.addActionListener(new WeakActionListener(new MyActionListener(), this.jButton1)) 

Вот реализация WeakActionListener:

public class WeakActionListener implements ActionListener { 

    private WeakReference weakListenerReference; 
    private Object source; 


    public WeakActionListener(ActionListener listener, Object source) { 
     this.weakListenerReference = new WeakReference(listener); 
     this.source = source; 
    } 

    public void actionPerformed(ActionEvent actionEvent) { 
     ActionListener actionListener = (ActionListener) this.weakListenerReference.get(); 
     if(actionListener == null) { 
      this.removeListener(); 
     } else { 
      actionListener.actionPerformed(actionEvent); 
     } 
    } 

    private void removeListener() { 
     try { 
      Method method = source.getClass().getMethod("removeActionListener", new Class[] {ActionListener.class}); 
      method.invoke(source, new Object[] {this}); 
     } catch(Exception ex) { 
      ex.printStackTrace(); 
     } 
    } 

} 

I профилировать оба приложения, используя JConsole для 1 4 часа. Я просто оставляю их бездействующими на этот период времени. Это показывает, что в обоих приложениях, использующих слабую ссылку или сильную ссылку, со временем увеличивается потребление кучи памяти.

Вопрос в том, является ли это ошибкой в ​​Java Swing API? Каковы другие альтернативы в решении этой проблемы утечки памяти?

Заранее благодарен!

+0

Вы говорите, что они сидят «без дела». Что еще происходит на машине, где они сидят? Вы сделали (или подумали) о каком-либо профилировании, чтобы узнать, какой код выполняется? Откуда вы получаете данные о потреблении кучи, а память не восстанавливается при сборе мусора? Вы смотрели какие-то свалки, чтобы увидеть, что занимает куча? На мой взгляд, постоянно потребляющая память отличается от утечки.Я думаю о утечке в том случае, когда память используется таким образом, что она больше не используется программой и не восстанавливается, поэтому программа никогда не может использоваться ею. – arcy

+0

Привет rcook! Спасибо за ответ. Я получаю свои данные от потребления памяти кучи JConsole. Основываясь на моем тесте, он может быть восстановлен сборкой мусора. –

+0

Тогда это не то, что я называю утечкой. Как насчет других вопросов? – arcy

ответ

2

JDK действительно содержит много утечек памяти, однако ситуация, которую вы описываете, не является одной из них. Объем потребления памяти, потому что даже когда приложение не работает, ОС нет - иногда он отправляет события ввода в приложение. Для обработки этих событий требуется некоторое выделение памяти, поэтому вы видите кучу грунта. И он, вероятно, не собирается, потому что ему не нужно - приложение имеет много свободной памяти в куче, поэтому это не GC слишком часто.

Кроме того, вы используете неправильный подход к анализу утечек памяти в Java. Правильный ответ будет следующим:

  1. Вы создаете простое возможное приложение с функциональностью, которую вы хотите проанализировать для утечек памяти.
  2. Вы делаете все шаги, после которых вы считаете, что память должна быть готова к GC. Для приложений, связанных с графическим интерфейсом, я предлагаю добавить вызов ((SunToolkit)Toolkit.getDefaultToolkit()).realSync() для обработки всех асинхронных вызовов и событий. Это внутренний API, поэтому его нельзя использовать в реальных приложениях, но это действительно полезно для таких экспериментальных приложений.
  3. После этого вы пытаетесь выделить какой-то большой объект, чтобы вызвать OutOfMemoryError. Вы можете быть уверены, что перед тем, как бросать OOME Java, вы соберете все свободные объекты. В улове блоке для OOME вы просто выйти из приложения с System.exit(0);

Теперь самым ineteresting части: вы должны запустить приложение с -Xmx20M установить низкую сумму памяти для кучи и -Xrunhprof:format=b,file=<Path to output file>. Поэтому, когда приложение заканчивается, вы уверены, что все свободные объекты GC'd из-за OutOfMemory, которые вы вызвали, и hprof сбросит кучу всех оставшихся объектов. Вы можете анализировать кучу с помощью одного из инструментов, доступных как jhat или некоторых инструментов из eclipse.