3

This thread, and this page:

It [OutOfMemoryError] will never be thrown unless the JVM tries a full garbage collection first, including removal of softly/weakly referenced objects.

As for this piece of code,

//.. allocate reserved memory
try {
    //.. calculation which requires alot of memory even after optimized
} catch (java.lang.OutOfMemoryError e){
    System.gc(); 
    //.. hedge recovery
}

Is the call to System.gc() redundant?

Is it already guaranteed that JVMs (according to JVMS) had run the GC before throwing java.lang.OutOfMemoryError?

Community
  • 1
  • 1
Pacerier
  • 86,231
  • 106
  • 366
  • 634
  • 4
    Again: Calls to System.gc() are almost never necessary or actually helpful. – Matthias Jan 06 '12 at 09:42
  • 4
    It's not an answer, so will put it as a comment: you should never try to "recover" after OOM. OOM means, some objects were not able to be created. Not only in your application: in libraries, too. That means, you have an application in a seriously broken state—and no way to find out what's broken. The best you can do is let the application die, and handle restart *externally*. – alf Jan 06 '12 at 09:43
  • 1
    @alf: Are you sure it would leave the application in a seriously broken state? You would not have "half-constructed" instances or "half-loaded" classes, right? It should still be as "sane" or not as after any other kind of exception. – Thilo Jan 06 '12 at 09:58
  • @Thilo yes I am. For example, you don't know in which threads OOM was thrown. And if there were threads not managed by your code, you won't find that these are no more. The main difference between "other kinds of exception" and OOM is that for exceptions (not `Error`s) you know the context and the scope of the problem. With OOM, it can be thrown on any allocation, not necessary in the calculation per se. So you generally don't know what exactly is dead, and at which stage. – alf Jan 06 '12 at 10:08
  • 1
    Why don't you know in which threads OOM were thrown? Each of those thread would get one, and they would either be caught or (cleanly) terminate the thread. It should be possible to recover from OOM (not saying that it is easy, but the JVM should not be in an inconsistent state like it does get into with Thread.stop for example). – Thilo Jan 06 '12 at 10:17
  • @alf, I'm not trying to recover. I'm trying to do a clean shutdown. – Pacerier Mar 19 '15 at 14:01

3 Answers3

8

You should never try to recover from an OutOfMemoryError by running System.gc(). Whether or not it's strictly guaranteed, you can probably find in the JLS. But it's pretty much a bad idea through and through - the JVM will try its hardest to fulfill your memory allocation desires. When it gives up and tosses an OOM, the game is up. Either reduce your memory usage or increase the heap size, and then try again.

To more directly answer your question, catching an OutOfMemoryError does not mean GC has run. For example

try {
    throw new OutOfMemoryError();
} catch (OutOfMemoryError e) {
    ;
}

will probably not invoke a GC. Obviously this is an absurd example. A more realistic one that I saw recently was an OOME with the cause "Could not allocate new native thread". Running GC would likely not resolve that sort of situation, as the JVM has heap space left but the system will not allow it more threads.

Steven Schlansker
  • 37,580
  • 14
  • 81
  • 100
6

From here:

Thrown when the Java Virtual Machine cannot allocate an object because it is out of memory, and no more memory could be made available by the garbage collector.

So, OutOfMemoryException is thrown after GC cannot free more memory.

Artem
  • 4,347
  • 2
  • 22
  • 22
  • I mean is this guaranteed behavior or may this vary between the different implementations of the Java Runtime? – Pacerier Jan 06 '12 at 09:48
  • I am not sure if having GC at all is a requirement... But for a given JVM the spec says it has to do everything it can before OOM. – Thilo Jan 06 '12 at 09:56
1

There are few different types of OutOfMemoryError. If we for example get OOME due to "Unable to create new native thread" then it's not necessarily due to GC invocation. The same with "Requested array size exceeds VM limit" - then we're going to allocate array larger than VM size calling GC is not needed. JVM is trying to do it's best and throwing OOME doesn't mean that it'll die soon. Also calling System.gc() for OOME caused by "GC overhead limit exceeded" makes no sense at all - it'll make the situation even worse.

Jakub Kubrynski
  • 13,724
  • 6
  • 60
  • 85