0

Edit: There is no memory leak, just a noobs misunderstanding of what the Netbeans Profiler is telling me. Live Profiling Results -> Allocated Objects refers to the TOTAL allocated over the lifetime of the program, not the total currently in memory. For that, get a heap dump. Sorry for the confusion, but maybe someone else will find this and it will clear that up for them.


Im using the NetBeans 7.0.1 profiler to troubleshoot memory growth in my application, and am seeing two major issues. Ive successfully created test applications and see the same results in the profiler, included below. I wasnt able to find a reference to these anywhere else.

Case 1: Looping through the entryset of a HashMap causes the object java.util.HashMap&EntryIterator to grow. Is there anything to do here except figure out a solution with a different container? Looping through the collection every time in the while loop is necessary to our application.

public static void main(String[] args) throws InterruptedException {
    boolean run = true;
    HashMap<Integer, Integer> map = new HashMap<Integer, Integer> ();
    map.put(1, 2);map.put(3, 4);map.put(5, 6);map.put(7, 8);
    while(true){
        for (Entry<Integer, Integer> entry : map.entrySet()) {
        Integer i = entry.getValue();
        }

        //app specific code here

        Thread.sleep(50);
    }
}

Case 2: Creating empty ArrayLists in a loop causes a growth of java.lang.Object[]. I would expect the ArrayLists to be eligible for GC at the end of the while loop. Is my assumption wrong? Or is something else at play here?

public static void main(String[] args) throws InterruptedException {
    boolean run = true;
    while(run){
        ArrayList<Integer> a1 = new ArrayList<Integer>();
        ArrayList<Integer> a2 = new ArrayList<Integer>();

        // app specific code here

        Thread.sleep(50);
    }
}
Mike K
  • 1
  • 1
  • 2
  • Is your assumption is that these objects are not reclaimed at the next GC cycle? Objects get created all over the place. It is the ones that have references to them that are the problem. – Gray Dec 02 '11 at 20:11
  • The memory might not be reclaimed until more memory is needed. Are you sure the garbage collector has run at all? – Roger Lindsjö Dec 02 '11 at 20:14
  • The issue was with the way I was interpreting the results of the Netbeans profiler. I took "Allocated Objects" to mean what is currently allocated, but It actually means number of objects created in the lifetime of the program. I knew this didnt look right. Sorry for the confusion all, and thanks for the responses. – Mike K Dec 02 '11 at 20:40
  • why don't you answer this question yourself with that? – Oleg Mikheev Dec 02 '11 at 21:29

6 Answers6

2

I don't think that either code sample is leaking memory. You must be sure to distinguish between "the heap grows until the garbage collector runs" and "the heap grows forever". If you remove the Thread.sleep calls and run either app forever it should not crash and the JVM's heap usage should rise and fall as the garbage collector runs. You can try running "System.gc()" during each loop and seeing if your profiler still shows a leak.

Spike Gronim
  • 6,154
  • 22
  • 21
  • Thanks for the quick response. I added System.gc() and am seeing the same results. But to be clear, Im seeing these in the Live Profiling Results, Allocated Objects list. When I look at Classes in the Heap Dump, I do not see them there. I think this may have been due to my own misunderstanding of what the profiler was telling me. If I understand correctly now, I was viewing the total allocations since the program started, and not what is currently being allocated. Is that correct? – Mike K Dec 02 '11 at 20:27
0

I have run the above code and I can confirm that this is not a memory leak. Because when I run the GC, all the ArrayList objects are reclaimed.Assumption is that it commented app code is not adding up to the issue

Regards, Lalitha

user1999099
  • 161
  • 1
  • 3
  • 8
0

Your ArrayLists in your second example would be eligible for GC as long as there is no other code that references them. In addition, you have no control over how and when a garbage collection is executed. Do you know what garbage collector you are using? Do you run your program with any specific vm flags? Do you experience strange behavior after you call System.gc in order to force a garbage collection? Does your app specific code reference your array lists?

Nikola Yovchev
  • 9,498
  • 4
  • 46
  • 72
0

In your both examples methods aint finishing hence even if GC runs it cannot claim these objects.

Even if your objects were initialized outside the loop then also on some compilers the bytecode would have been same as they were created inside loop, there is not much of a difference.

Moreover you cannot guarantee if GC will ever run and your objects will be reclaimed.

EDIT:

Similar post on SO

Community
  • 1
  • 1
mprabhat
  • 20,107
  • 7
  • 46
  • 63
  • Why would the method need to finish? Would they not be eligible for GC once they are out of scope (the end of the loop)? – Mike K Dec 02 '11 at 20:30
0

Although I can't find anything disturbing, I just tried both of your code snippets. I removed sleeps to speed up testing. Garbage collector works like crazy several times per second and essentially cleans the whole young generation (try with -XX:+PrintGCDetails -XX:+PrintGCTimeStamps):

[GC [PSYoungGen: 104272K->0K(99712K)] 105235K->963K(131968K), 0.0008090 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]

The code run for few minutes with very high CPU utilization, but memory usage was stable. There is definitely no memory leak in both code samples.

What you are probably observing is incremental growth of heap (young generation in JVM is basically a stack, allocating new objects on top of each other and not bothering about garbage). The garbage collection runs when the stack is exhausted.

Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674
0

A lot of what you're saying depends upon the lines like:

// app specific code here

What you're doing here can affect the garbage collection a lot. For the code you've posted, this will cause memory leaks. For instance, each time through this loop:

public static void main(String[] args) throws InterruptedException {
    boolean run = true;
    while(run){
        ArrayList<Integer> a1 = new ArrayList<Integer>();
        ArrayList<Integer> a2 = new ArrayList<Integer>();

        // app specific code here

        Thread.sleep(50);
    }
}

the objects allocated become available for garbage collection. The memory may continue to grow until it reaches its allocated limit, but after that the objects will be garbage collected.

Run your code outside netbeans, and run jvisualvm on it. See what is really happening.

Matthew Farwell
  • 60,889
  • 18
  • 128
  • 171