Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detecting memory-leak programmatically

If, on purpose, I create an application that crunches data while suffering from memory-leaks, I can notice that the memory as reported by, say:

Runtime.getRuntime().freeMemory()

starts oscillating between 1 and 2 MB of free memory.

The application then enters a loop that goes like this: GC, processing some data, GC, etc. but because the GC happens so often, the application basically isn't doing much else anymore. Even the GUI takes age to respond (and, no, I'm not talking about EDT issues here, it's really the VM basically stuck in some endless GC'ing mode).

And I was wondering: is there a way to programmatically detect that the JVM doesn't have enough memory anymore?

Note that I'm not talking about ouf-of-memory errors nor about detecting the memory leak itself.

I'm talking about detecting that an application is running so low on memory that it is basically calling the GC all the time, leaving hardly any time to do something else (in my hypothetical example: crunching data).

Would it work, for example, to repeatedly read how much memory is available during, say, one minute, and see that if the number has been "oscillating" between different values all below, say, 4 MB, conclude that there's been some leak and that the application has become unusable?

like image 733
SyntaxT3rr0r Avatar asked Nov 24 '10 23:11

SyntaxT3rr0r


2 Answers

And I was wondering: is there a way to programmatically detect that the JVM doesn't have enough memory anymore?

I don't think so. You can find out roughly how much heap memory is free at any given instant, but AFAIK you cannot reliably determine when you are running out of memory. (Sure, you can do things like scraping the GC log files, or trying to pick patterns in the free memory oscillations. But these are likely to be unreliable and fragile in the face of JVM changes.)

However, there is another (and IMO better) approach.

In recent versions of Hotspot (version 1.6 and later, I believe), you can tune the JVM / GC so that it will give up and throw an OOME sooner. Specifically, the JVM can be configured to check that:

  • the ratio of free heap to total heap is greater than a given threshold after a full GC, and/or
  • the time spent running the GC is less than a certain percentage of the total.

The relevant JVM parameters are "UseGCOverheadLimit", "GCTimeLimit" and "GCHeapFreeLimit". Unfortunately, Hotspot's tuning parameters are not well documented on the public web, but these ones are all listed here.

Assuming that you want your application to do the sensible thing ... give up when it doesn't have enough memory to run properly anymore ... then just launch the JVM with a smaller "GCTimeLimitor" or "GCHeapFreeLimit" than the defaults.

EDIT

I've discovered that the MemoryPoolMXBean API allows you to look at the peak usage of individual memory pools (heaps), and set thresholds. However, I've never tried this, and the APIs have lots of hints that suggest that not all JVMs implement the full API. So, I would still recommend the HotSpot tuning option approach (see above) over this one.

like image 59
Stephen C Avatar answered Oct 08 '22 21:10

Stephen C


You can use getHeapMemoryUsage.

like image 41
Martin v. Löwis Avatar answered Oct 08 '22 21:10

Martin v. Löwis