SyntaxT3rr0r
SyntaxT3rr0r

Reputation: 28293

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?

Upvotes: 8

Views: 2772

Answers (7)

bsautner
bsautner

Reputation: 4812

i've been using plumbr for memory leak detection and it's been a great experience, though the licence is very expensive: http://plumbr.eu/

Upvotes: 0

Stephen C
Stephen C

Reputation: 718778

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.

Upvotes: 3

Persimmonium
Persimmonium

Reputation: 15791

I think the JVM does exactly this for you and throws java.lang.OutOfMemoryError: GC overhead limit exceeded. So if you catch OutOfMemoryError and check for that message then you have what you want, don't you?

See this question for more details

Upvotes: 0

Amir Afghani
Amir Afghani

Reputation: 38531

What you could do is spawn a thread that wakes up periodically and calculates the amount of used memory and records the result. Then you can do regression analysis on the result to estimate the rate of memory growth in your application. If you know the rate of growth, and the maximum amount of memory, you can predict (with some confidence) when your application will run out of memory.

Upvotes: 1

Martin v. Löwis
Martin v. Löwis

Reputation: 127447

You can use getHeapMemoryUsage.

Upvotes: 2

Jens Schauder
Jens Schauder

Reputation: 81882

I see two attack vectors.

Either monitor your memory consumption.

When you more or less constantly use lots of the available memory it is very likely that you have a memory leak (or are just using too much memory). The vm will constantly try to free some memory without much success => constant high memory usage.

You need to distinguish that from a large zigzag pattern which happens often without being an indicator of memory problem. Basically you use more an more memory, but when gc finds time to do its job it finds lots of garbage to bring out, so everything is fine.

The other attack vector is to monitor how often and what kind of success the gc runs. If it runs often with only small gains in memory, it is likely you have a problem.

I don't know if you can access this kind of information directly from your program. But if nothing else I think you can specify parameters on startup which makes the gc log information into a file which in turn could get parsed.

Upvotes: 1

hhafez
hhafez

Reputation: 39750

You can pass arguments to your java virtual machine that gives you GC diagnostics such as

  1. -verbose:gc This flag turns on the logging of GC information. Available in all JVMs.

  2. -XX:+PrintGCTimeStamps Prints the times at which the GCs happen relative to the start of the application.

If you capture that output in a file, in your application you can periodcly read that file and parse it to know when the GC has happened. So you can work out the average time between every GC

Upvotes: 0

Related Questions