4

I have a Java application that waits for the user to hit a key and then runs a task. Once done, it goes back and waits again. I was looking at memory profile for this application with jvisualvm, and it showed an increasing pattern.

Committed memory size is 16MB. Used memory, on application startup, was 2.7 MB, and then it climbed with intermediate drops (garbage collection). Once this sawtooth pattern approached close to 16MB, a major drop occurred and the memory usage fell close to 4 MB. This major drop point has been increasing though. 4MB, 6MB, 8MB. The usage never goes beyond 16 MB but the whole sawtooth pattern is on a climb towards 16 MB.

Do I have a memory leak?

Since this is my first time posting to StackOverflow, do not have enough reputation to post an image.

Michael Petrotta
  • 59,888
  • 27
  • 145
  • 179
archana
  • 43
  • 3
  • Doesn't look like it. This looks like a normal GC pattern. If your memory usage were rising without bound, I'd worry. – user2357112 Dec 05 '13 at 23:59

3 Answers3

2

That kind of sawtooth pattern is commonly observed and is not an indication of memory leak.

Because garbage collecting in big chunks is more efficient than constantly collecting small amounts, the JVM does the collecting in batches. That's why you see this pattern.

Enno Shioji
  • 26,542
  • 13
  • 70
  • 109
  • But the mem used is not anywhere near the initial mem usage of 2.7 MB. Is this ok? – archana Dec 06 '13 at 00:04
  • Initial memory usage isn't really the best thing to compare against. You'd want to compare with the heap you allocated (e.g. via the `Xmx` option – Enno Shioji Dec 06 '13 at 00:09
2

Modern SunOracle JVMs use what is called a generational garbage collector:

  1. When the collector runs it first tries a partial collection only releases memory that was allocated recently
  2. recently created objects that are still active get 'promoted'
  3. Once an object has been promoted a few times, it will no longer get cleaned up by partial collections even after it is ready for collection
  4. These objects, called tenured, are only cleaned up when a full collection becomes necessary in order to make enough room for the program to continue running

So basically, bits of your program that stick around long enough to get missed by the fast 'partial' collections will hang around until JVM decides it has to do a full collection. If you let it go long enough you should eventually see the full collection happen and usage drop back down to your original starting point.

If that never happens and you eventually get an Out Of Memory exception, then you probably have a memory leak :)

Affe
  • 47,174
  • 11
  • 83
  • 83
0

As stated by others, this behavior is normal. This is a good description of the garbage collection process. To summarize, the JVM usese a generational garbage collector. The vast majority of objects are very short-lived, and those that survive longer tend to last much longer. Knowing this, the GC will check the newer generation first to avoid having to repeatedly check the older objects which are less likely to be inaccessible. After a period of time, the survivors move to the older generation. This increasing saw-tooth is exactly what you're seeing- the rising troughs are due to the older generation growing larger as the survivors are being moved to it. If your program ran long enough eventually checking the newer generation wouldn't free up enough memory and it would have to GC the old generation as well.

Hope that helps.

Floegipoky
  • 3,087
  • 1
  • 31
  • 47
  • For experimentation purposes, you can "force" garbage collection with `System.gc()`. If you do this several times repeatedly you can often force it to perform a full collection, and you'll be able to see the memory profile return to a baseline (increased slightly to account for the older gen objects that are still "in use"). – Floegipoky Dec 06 '13 at 00:19
  • I found [this](http://www.oracle.com/technetwork/java/whitepaper-135217.html#garbage) other resource on the GC today – Floegipoky Dec 10 '13 at 22:20