3

I'm currently investigating a memory leak in one of our applications. After further investigation, I came up with a test of two simple java swing applications that sit idle for almost 14 hours. Both applications consist of 30 JButtons.

The 1st application is using a strong reference for its action listener:

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

The 2nd application is using a weak reference for its action listener:

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

Here's the WeakActionListener implementation:

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 profile both applications using JConsole for 14 hours. I just leave them idle for that time frame. It shows that both applications either using weak reference or strong reference have an increasing memory heap consumption over time.

My question is, is this a bug in Java Swing API? What are the other alternatives in resolving this kind of memory leak?

Thanks in advance!

Adan Kuwenyo
  • 53
  • 1
  • 8
  • You say they sit "idle". What else is going on on the machine where they sit? Have you done (or thought about) any profiling to see what code is executing? From where do you get your figures for heap consumption, and is the memory unrecoverable by garbage collection? Have you looked at any dumps to see what is occupying the heap? Constantly consuming memory is, to my mind, different than a leak. I think of a leak as a case where memory is used in such a way that it is no longer used by the program and is not recoverable so that it can't ever BE used by the program. – arcy Mar 26 '13 at 02:25
  • Hi rcook! Thanks for the reply. I get my figures from JConsole Heap Memory Consumption. Based on my test it can be recovered by garbage collection. – Adan Kuwenyo Mar 26 '13 at 02:33
  • Then it isn't what I call a leak. How about the other questions? – arcy Mar 26 '13 at 02:33
  • The machine is locked and the screen is off. Can you recommend a good and free profiler other than the one built-in in NetBeans? – Adan Kuwenyo Mar 26 '13 at 02:34
  • No, have never used one myself. My own next step would be the dump analyzer; what objects are occupying the memory and where they are referenced from is bound to be interesting. Good luck. – arcy Mar 26 '13 at 02:35
  • The initial heap memory consumption is 2MB. After 14 hours, it is increasing and reached 5MB. Does performing System.gc() a good option to reclaim those memory? – Adan Kuwenyo Mar 26 '13 at 02:35
  • Does a dump analyzer different from a profiler? Or it is a part of a profiler? – Adan Kuwenyo Mar 26 '13 at 02:37
  • If you will go to the java chat room, it seems we might do some good there. – arcy Mar 26 '13 at 02:39
  • Sorry I still don't have enough reputation to go to the chat room. I appreciated your help rcook, thank you so much. I will try the dump analyzer and will update this thread for the result. – Adan Kuwenyo Mar 26 '13 at 02:45
  • sorry, that hadn't occurred to me. Dump is a file representing the heap that you can get from a running/crashed program, and a dump analyzer deals with that. profiler is code that analyzes your program as it is running. That's the difference – arcy Mar 26 '13 at 02:47
  • jvisualvm works pretty well for profiling this sort of thing. Honestly, if the GC recovers the memory, then I don't understand what the purpose of the question is. It is very normal for an application's heap to grow and shrink. – Kevin Day Mar 26 '13 at 03:55
  • 1
    For [example](http://stackoverflow.com/a/6310284/230513). – trashgod Mar 26 '13 at 04:34
  • Hi Kevin! This one is for a simple application. Our application reaches 500MB+ over time and crashes if the physical memory of the client exceeded. – Adan Kuwenyo Mar 26 '13 at 05:28

1 Answers1

2

JDK actually contains a lot of memory leaks, however the situation you are discribing is not the one of them. The memory consumption grous because even when the app is idle, the OS is not - it sends input events to the app sometimes. Handling these events requires some memory allocations, therefor you see a grouwing heap. And it is probably not collected, because it does not need to - the app has plenty of free memory in the heap, so it does not GC too often.

Additionally, you are using a wrong approach to memory leaks analysis in Java. The right one would be the following:

  1. You create the simplet possible app with the functionality you want to analyse for memory leaks.
  2. You do all steps after which you think the memory should be ready for GC. For GUI-related apps I suggest to add a call to ((SunToolkit)Toolkit.getDefaultToolkit()).realSync() to process all asynchronous calls and events. This is an internal API, so it should not be ised on the real apps, but it is really useful for such experimental apps.
  3. After that you try to allocate some big object to cause an OutOfMemoryError. You can be sure that before throwing OOME Java will collect all free objects. In the catch block for the OOME you simply exit the app with System.exit(0);

Now the most ineteresting part: you should run the app with -Xmx20M to set a low ammount of memory for the heap and -Xrunhprof:format=b,file=<Path to output file>. So when the app finishes, you are sure that all free objects are GC'd because of the OutOfMemory you've caused and hprof will dump a heap of all objects left. You can analize the heap with one of the tools available like jhat or some tools from eclipse.

Petr
  • 5,999
  • 2
  • 19
  • 25