Hi All, I stumbled across a scenario where calling show() and dispose() on JFrames causes memory to creep up and never get released. So, I wrote this simple test that shows this. When you start the test, (with no JVM parameters) the memory from Task Manager shows about 10MB. This will very slowly but continually creep up until you run out of memory. I ran it for 3 days and the memory got up to 98MB. Even after running System.gc() after every 100 iterations, I get the same results. Does anyone see a reason why this should happen? I would like for someone else to confirm that this is a Java bug. Thanks, Barry
[ May 29, 2002: Message edited by: Barry Andrews ]
I observe the same sort of behavior even when there's only one frame. By using Runtime's totalMemory() and freeMemory() methods, it looks as though the heap size is unaffected by all this (on average, that is). Yet looking at the task manager, I see the memory usage allocated to java.exe very slowly rising. Here's the code I'm using:
I also get similar results by replacing show() and dispose() with setVisible(true) and setVisible(false). Not sure what that means though. I have the feeling this is buried somewhere in native code, and thus could be very platform-specific. I'm using Java 2 SDK 1.4 on Windows NT at the moment, for what it's worth.
I was seeing this with Java 1.4 on Windows XP. So Jim, you think that the Task Manager is not reporting memory usage correctly? I will use the Runtime.freeMemory() and totalMemory() in my test case tomorrow and see what happens. Thanks, Barry
I wonder if this is just simple confusion on how the JVM grows the heap? There are two parameters : initial heap size, and max heap size. When the JVM first starts, it tries to allocate the initial heap size in RAM from the underlying OS. During program execution, as objects are created and destroyed, the JVM will try to accomodate all memory requests via some internal algorithm, but basically, there are two ways to fulfill a request for a new object when memory is low in the current JVM heap : either run the gc to free up memory to get the memory you need, OR, grow the JVM heap, up to the max set by the max heap size parameter. So it's not surprising that over time, the size of the JVM heap, as reported by OS tools, grows. This is normal. It will grow up to the max heap size, and no more. (Note that as a further wrinkle, you can actually request a larger heap size than physically available RAM on the machine. The OS can provide virtual RAM to the JVM, but of course this will severly degrade performance as you start getting page faults, and most client OSes aren't designed for efficient use of virtual memory). [ May 29, 2002: Message edited by: Rob Ross ]
Joined: Jan 30, 2000
I was seeing this with Java 1.4 on Windows XP. So Jim, you think that the Task Manager is not reporting memory usage correctly? No, that's not it. The Task Manager and the Runtime methods are reporting different things. The Task Manager is reporting the total memory taken up by everything in the JVM, while totalMemory and freeMemory refer only to the heap - the memory used by Java objects. At least, I think that's the distinction. So what the output of my program above tells me is that the heap is not growing, but something else in the JVM is. Rob's discussion is true in general, but I don't think it applies here, as the heap isn't growing. The memory used rises and falls a bit, but it's well below the totalMemory(). And even if random fluctuations might occasionally force the JVM size to increase, what I see is slow but consistent growth in the JVM, which doesn't seem to be accounted for by heap fluctuations. As an aside, on other occasions I actually have sometimes seen JVM memory allocations decrease in size. Evidently some JVM's are smart enough to notice when they've got more memory allocated than they need. In some situations at least - I never determined a consistent pattern.
After running my test again with the totalMemory() and freeMemory() method calls, I see what everyone else sees, i.e. Task Manager shows memory creep while totalMemory() call shows constant size and freeMemory() goes up and down, but is never excessive. But even when you first start a program, it seems that the VM size reported in Task Manager is about twice the size of what totalMemory() reports. I would think these would be the same. Also, is it possible that Task Manager does not recognize garbage collection, thus cauing the size to grow indefinitely?? What I would like to do is run this test for a few days on a machine that does not have a lot of memory (64MB) and see what happens when Task Manager says I am using all of the 64MB. Will JVM crash or not? I will see.
Barry [ May 30, 2002: Message edited by: Barry Andrews ]
Joined: Jan 30, 2000
But even when you first start a program, it seems that the VM size reported in Task Manager is about twice the size of what totalMemory() reports. I would think these would be the same. Again, they measure different things. I believe totalMemory() just reports the available heap size - the memory which could be used by objects. The task manager should report all memory used by the JVM. This does not seem to include the part of totalMemory() represented by freeMemory() (hte unused part of the heap) - but it does include storage of all the machine code that tells the JVM what to do from moment to moment, and all the loaded class definitions - not their data (which is in the heap), but the method code. All that stuff takes memory too. And it can also include memory allocated by native method calls, which wouldn't be considered part of the heap. I suspect that's the case here. GUI's ultimately rely on native methods to get many things done. Also, is it possible that Task Manager does not recognize garbage collection, thus causing the size to grow indefinitely?? Doubtful. That would be a serious problem. If the task manager thinks a program takes X memory, then so does the rest of the operating system, most likely. Which means that other programs would be limited to (totalMem - X) to run in, even if X is bigger than it needs to be. We'd all have serious problems running any other programs along with a JVM if the effects of garbage collection were not recognized externally.
Again, they measure different things. I believe totalMemory() just reports the available heap size - the memory which could be used by objects. The task manager should report all memory used by the JVM.
Yes, I understand now what you mean by this. Now, back to the original problem... After running my test for 24 hours on 2 different machines, here are my findings.
Not sure what all this means since I have 2 different variables here, i.e. 2 operating systems and 2 versions of Java SDKs, but my theory is that 1.4 garbage collection is better. It still doesn't explain why Task Manager on the 1.4 environment shows memory constantly growing, unless the JVM itself has got memory leaks. This could be bad. What are your thoughts? Barry Sorry about the format of the findings. I tried to make a table, but not successful. Hopefully it makes sense. [ May 31, 2002: Message edited by: Barry Andrews ] [ Added code tags for formatting - Jim ] [ May 31, 2002: Message edited by: Jim Yingst ]