210

I am aware that every object requires heap memory and every primitive/reference on the stack requires stack memory.

When I attempt to create an object on the heap and there's insufficient memory to do so, the JVM creates an java.lang.OutOfMemoryError on the heap and throws it to me.

So implicitly, this means that there is some memory reserved by the JVM on startup.

What happens when this reserved memory is used up (it would definitely be used up, read discussion below) and the JVM does not have enough memory on the heap to create an instance of java.lang.OutOfMemoryError?

Does it just hang? Or would he throw me a null since there's no memory to new an instance of OOM ?

try {
    Object o = new Object();
    // and operations which require memory (well.. that's like everything)
} catch (java.lang.OutOfMemoryError e) {
    // JVM had insufficient memory to create an instance of java.lang.OutOfMemoryError to throw to us
    // what next? hangs here, stuck forever?
    // or would the machine decide to throw us a "null" ? (since it doesn't have memory to throw us anything more useful than a null)
    e.printStackTrace(); // e.printStackTrace() requires memory too.. =X
}

==

Why couldn't the JVM reserve sufficient memory?

No matter how much memory is reserved, it is still possible for that memory to be used up if the JVM does not have a way to "reclaim" that memory:

try {
    Object o = new Object();
} catch (java.lang.OutOfMemoryError e) {
    // JVM had 100 units of "spare memory". 1 is used to create this OOM.
    try {
        e.printStackTrace();
    } catch (java.lang.OutOfMemoryError e2) {
        // JVM had 99 units of "spare memory". 1 is used to create this OOM.
        try {
            e.printStackTrace();
        } catch (java.lang.OutOfMemoryError e3) {
            // JVM had 98 units of "spare memory". 1 is used to create this OOM.
            try {
                e.printStackTrace();
            } catch (java.lang.OutOfMemoryError e4) {
                // JVM had 97 units of "spare memory". 1 is used to create this OOM.
                try {
                    e.printStackTrace();
                } catch (java.lang.OutOfMemoryError e5) {
                    // JVM had 96 units of "spare memory". 1 is used to create this OOM.
                    try {
                        e.printStackTrace();
                    } catch (java.lang.OutOfMemoryError e6) {
                        // JVM had 95 units of "spare memory". 1 is used to create this OOM.
                        e.printStackTrace();
                        //........the JVM can't have infinite reserved memory, he's going to run out in the end
                    }
                }
            }
        }
    }
}

Or more concisely:

private void OnOOM(java.lang.OutOfMemoryError e) {
    try {
        e.printStackTrace();
    } catch (java.lang.OutOfMemoryError e2) {
        OnOOM(e2);
    }
}
Keith Pinson
  • 7,835
  • 7
  • 61
  • 104
Pacerier
  • 86,231
  • 106
  • 366
  • 634
  • 2
    your answer would be JVM dependent to a great extent – MozenRath Feb 13 '12 at 13:57
  • 23
    One telephony library I once used (in the 90's) used to catch the `OutOfMemoryException` and then do something which involved creating a large buffer... – Tom Hawtin - tackline Feb 13 '12 at 14:23
  • @TomHawtin-tackline What if the operations involved in doing that throws another OOM ? – Pacerier Feb 13 '12 at 14:26
  • "When I attempt to create an object on the heap and there's insufficient memory to do so, the JVM creates an java.lang.OutOfMemoryError on the heap and throws it to me" that is not very likely, it throws when there is no contiguous virtual address space for the object or the allocation is too fast and IO cannot swap pages fast enough. – Lukasz Madon Feb 13 '12 at 18:14
  • 38
    Like a cellphone, it runs out of battery but it has the enough battery to keep spamming "You're running out of battery". – Kazuma Feb 13 '12 at 22:13
  • 1
    "What happens when this reserved memory is used up": that could happen only if the program caught the first `OutOfMemoryError` and retained a reference to it. It transpires that catching a `OutOfMemoryError` is not as useful as one might think, because you can guarantee **almost nothing** about the state of your program on catching it. See http://stackoverflow.com/questions/8728866/no-throw-virtualmachineerror-guarantees – Raedwald Feb 14 '12 at 13:05

11 Answers11

147

The JVM never really runs out of memory. It does memory computation of the heap stack in advance.

The Structure of the JVM, Chapter 3, section 3.5.2 states:

  • If Java virtual machine stacks can be dynamically expanded, and expansion is attempted but insufficient memory can be made available to effect the expansion, or if insufficient memory can be made available to create the initial Java virtual machine stack for a new thread, the Java virtual machine throws an OutOfMemoryError.

For Heap, Section 3.5.3.

  • If a computation requires more heap than can be made available by the automatic storage management system, the Java virtual machine throws an OutOfMemoryError.

So, it does a computation in advance before doing allocation of the object.


What happens is that the JVM tries to allocate memory for an object in the memory called Permanent Generation region (or PermSpace). If allocation fails (even after the JVM invokes the Garbage Collector to try & allocate free space), it throws an OutOfMemoryError. Even exceptions requires a memory space so the error will be thrown indefinitely.

Further reading.? Furthermore, OutOfMemoryError can occur in different JVM structure.

Buhake Sindi
  • 87,898
  • 29
  • 167
  • 228
  • 10
    I mean yes, but wouldn't the Java virtual machine also need memory to throw an OutOfMemoryError? What happens when there's no memory to throw an OOM? – Pacerier Feb 13 '12 at 15:19
  • I don't think the JVM fully uses all it's memory. the JVM keeps private stack for its internal method calls/storing variables, etc. Thus, the JVM always has some memory. It should have memory allocated at start-up for `Error` such as `OutOfMemoryError`. – Buhake Sindi Feb 13 '12 at 15:32
  • 5
    But if the JVM doesn't return the reference to the same instance of an OOM, don't you agree that eventually it would run out of it's reserved memory? (as demonstrated in the code in the question) – Pacerier Feb 13 '12 at 15:40
  • 1
    Allow me to put a reference to Graham's comment here: http://stackoverflow.com/questions/9261705/what-happens-when-theres-insufficient-memory-to-throw-an-outofmemoryerror#comment-11672364 – Pacerier Feb 13 '12 at 15:42
  • 1
    @martin, not true. There are other memory that the JVM creates, a private memory that doesn't share resources with java heap space. – Buhake Sindi Feb 13 '12 at 19:54
  • 2
    Might be nice if the VM retained a singleton of OOM Exception for the extreme case stated, and at a nuclear power plant. – John K Feb 14 '12 at 04:57
  • 8
    @JohnK: I would hope nuclear power plants are not programmed in Java, just like space shuttles and Boeing 757s are not programmed in Java. – Dietrich Epp Feb 14 '12 at 07:11
  • @JohnK, if you hit OOM, the program is virtually dead (unless it's single threaded), the OOM can hit any well-behaved thread at any point but OOMs are not are to deal w/, the real hard ones are StackOverflows since they can hit the native code and absolutely kill the process. – bestsss Feb 14 '12 at 08:54
  • 1
    Although accepted, this answer is incorrect. The PermGen is only used for instances of java.lang.Class and other various "permanent" structures. Furthermore, as other people have pointed out, a "reserve" OutOfMemoryError is allocated in JVM initialization so that no allocation needs to occur to throw the OOME. – ahawtho Oct 14 '13 at 21:07
64

Graham Borland seems to be right: at least my JVM apparently re-uses OutOfMemoryErrors. To test this, I wrote a simple test program:

class OOMTest {
    private static void test (OutOfMemoryError o) {
        try {
            for (int n = 1; true; n += n) {
                int[] foo = new int[n];
            }
        } catch (OutOfMemoryError e) {
            if (e == o)
                System.out.println("Got the same OutOfMemoryError twice: " + e);
            else test(e);
        }
    }
    public static void main (String[] args) {
        test(null);
    }
}

Running it produces this output:

$ javac OOMTest.java && java -Xmx10m OOMTest 
Got the same OutOfMemoryError twice: java.lang.OutOfMemoryError: Java heap space

BTW, the JVM I'm running (on Ubuntu 10.04) is this:

$ java -version
java version "1.6.0_26"
Java(TM) SE Runtime Environment (build 1.6.0_26-b03)
Java HotSpot(TM) 64-Bit Server VM (build 20.1-b02, mixed mode)

Edit: I tried to see what would happen if I forced the JVM to run completely out of memory using the following program:

class OOMTest2 {
    private static void test (int n) {
        int[] foo;
        try {
            foo = new int[n];
            test(n * 2);
        }
        catch (OutOfMemoryError e) {
            test((n+1) / 2);
        }
    }
    public static void main (String[] args) {
        test(1);
    }
}

As it turns out, it seems to loop forever. However, curiously, trying to terminate the program with Ctrl+C doesn't work, but only gives the following message:

Java HotSpot(TM) 64-Bit Server VM warning: Exception java.lang.OutOfMemoryError occurred dispatching signal SIGINT to handler- the VM may need to be forcibly terminated

Community
  • 1
  • 1
Ilmari Karonen
  • 49,047
  • 9
  • 93
  • 153
  • Nice test, same for me with version "1.7.0_01" Java HotSpot(TM) 64-Bit Server VM – Pacerier Feb 13 '12 at 17:40
  • Interesting. That makes it look like the JVM doesn't completely understand tail recursion... (As if it's doing some tail-recursive stack reuse, but not quite enough to clean up all the memory...) – Izkata Feb 13 '12 at 19:02
  • Modified your code to see how many different ones I get -- I always get the else branch executed exactly 5 times. – Irfy Feb 13 '12 at 19:13
  • @Izkata: I'd rather say it's a conscious decision to pre-allocate `n` OOMs and reuse one of them afterwards, so that an OOM can *always* be thrown. Sun/Oracle's JVM doesn't support tail recursion at all IIRC? – Irfy Feb 13 '12 at 19:19
  • @Irfy Probably not. I don't actually know, but that section of code looks like it would have optimized it away if it was supported. It's the "seems to loop forever" that has me confused =P – Izkata Feb 13 '12 at 19:33
  • @Izkata In fact, the JVM **does not** understand tail recursion and optimize it away, at least not the way C / C++ does, and there's a very real chance of overflowing your stack. The reasons for it are numerous and easy to find here on SO, including but not limited to remote debugging capabilities etc. – TC1 Feb 13 '12 at 19:36
  • 10
    @Izkata The loop is running apparently endlessly because the JVM is constantly throwing one and the same (5th or so) OOM after it runs out of memory. So it has `n` frames on the stack and it ends up creating and destroying frame `n+1` for eternity, giving the appearance of running endlessly. – Irfy Feb 13 '12 at 19:40
  • Your program runs forever because ((n+1)/2)*2 = n in Java, if n is a positive even integer (At least this is how C and C++ do it; I would image Java does also) – Demi Sep 12 '13 at 00:23
  • @Demetri: Yes, that's how it's supposed to work. The `+1` is there just to ensure that odd values (specifically 1) are rounded up. What the second program above _does_ is allocate exponentially larger and larger blocks of memory until an allocation fails, then reduce the block size exponentially until an allocation succeeds again, and repeat. That way, it efficiently grabs and hangs on to _any_ free heap space it can get. – Ilmari Karonen Sep 12 '13 at 13:02
41

Most runtime environments will pre-allocate on startup, or otherwise reserve, enough memory to deal with memory starvation situations. I imagine most sane JVM implementations would do this.

Graham Borland
  • 60,055
  • 21
  • 138
  • 179
  • 1
    http://stackoverflow.com/questions/9261215/what-operations-will-never-throw-stackoverflowerror#comment-11672052 : True but if the JVM reserved 100 units of memory to do that, and spent 1 unit on the first OOM, what happens if in my OOM catch block I do e.printStackTrace()? e.printStackTrace() requires memory too. Then the JVM would spend another unit of memory to throw me another OOM (98 units left) and I catch that with a e.printStackTrace() so the JVM throws me another OOM (97 units left) and well that is caught and I wanted.. – Pacerier Feb 13 '12 at 14:04
  • to e.printStackTrace() that as well.. If there's no way for the JVM to "reclaim" the memory it had reserved, he will run out of it anyway no matter how much is reserved in the first place. – Pacerier Feb 13 '12 at 14:04
  • 3
    This is exactly why OOME never used to include a stack trace — stack traces take memory! OOME only started attempting to include a stack trace in java 6 (https://blogs.oracle.com/alanb/entry/outofmemoryerror_looks_a_bit_better). I assume that if the stack trace isn't possible, then the exception is thrown without a stack trace. – Sean Reilly Feb 13 '12 at 14:07
  • 1
    @SeanReilly I mean an exception that doesn't have a stack trace is still an Object, which still requires memory. Memory is needed regardless of whether a stack trace is provided. Is it true that in the catch block if there's no memory left to create an OOM (no memory to create even one without stack trace), then I would catch a null? – Pacerier Feb 13 '12 at 14:09
  • 17
    The JVM could return multiple references to a single static instance of the OOM exception. So even if your `catch` clause attempts to use more memory, the JVM can just keep throwing the same OOM instance over and over again. – Graham Borland Feb 13 '12 at 14:13
  • @Pacerier, No offense to you, but there are better answers below (Considering some have put links to the JVM specification stating how JVM allocates memory). – Buhake Sindi Feb 13 '12 at 14:59
  • I agree, other answers are better than mine. :) – Graham Borland Feb 13 '12 at 15:02
  • 1
    @TheEliteGentleman I agree that those are very good answers too, but the JVM lives on a physical machine, Those answers did not explain how the JVM could magically have sufficient memory to always provide an instance of OOM. *"It's always the same instance"* seems to solve the riddle. – Pacerier Feb 13 '12 at 15:06
  • @Pacerier, I disagree. The specs states that it does computation for memory allocation before assigning memory. See my answer. It doesn't allocate memory and then finds out that there isn't enough & throw exception. – Buhake Sindi Feb 13 '12 at 15:14
23

Last time I was working in Java and using a debugger, the heap inspector showed that the JVM allocated an instance of OutOfMemoryError on startup. In other words, it allocates the object before your program has a chance to start consuming, let alone run out of, memory.

benzado
  • 82,288
  • 22
  • 110
  • 138
12

From the JVM Spec, Chapter 3.5.2:

If Java virtual machine stacks can be dynamically expanded, and expansion is attempted but insufficient memory can be made available to effect the expansion, or if insufficient memory can be made available to create the initial Java virtual machine stack for a new thread, the Java virtual machine throws an OutOfMemoryError.

Every Java Virtual Machine has to guarantee that it will throw an OutOfMemoryError. That implies, that it has to be capable of creating an instance of OutOfMemoryError (or haveing on created in advance) even if there's no heap space left.

Although it does not have to guarantee, that there's enough memory left to catch it and print a nice stacktrace...

Addition

You added some code to show, that the JVM might run out of heap space if it had to throw more than one OutOfMemoryError. But such an implementation would violate the requirement from above.

There is no requirement that the thrown instances of OutOfMemoryError are unique or created on demand. A JVM could prepare exactly one instance of OutOfMemoryError during startup and throw this whenever it runs out of heap space - which is once, in normal environment. In other words: the instance of OutOfMemoryError that we see could be a singleton.

Andreas Dolk
  • 113,398
  • 19
  • 180
  • 268
11

Interesting question :-). While the others have given good explanations of the theoretical aspects, I decided to try it out. This is on Oracle JDK 1.6.0_26, Windows 7 64 bit.

Test setup

I wrote a simple program to exhaust memory (see below).

The program just creates a static java.util.List, and keeps stuffing fresh strings into it, until OOM is thrown. It then catches it and continues stuffing in an endless loop (poor JVM...).

Test result

As one can see from the output, the first four times OOME is thrown, it comes with a stack trace. After that, subsequent OOMEs only print java.lang.OutOfMemoryError: Java heap space if printStackTrace() is invoked.

So apparently the JVM makes an effort to print a stack trace if it can, but if memory is really tight, it just omits the trace, just like the other answers suggest.

Also interesting is the hash code of the OOME. Note that the first few OOME all have different hashes. Once the JVM starts omitting stack traces, the hash is always the same. This suggests that the JVM will use fresh (preallocated?) OOME instances as long as possible, but if push comes to shove, it will just reuse the same instance rather than having nothing to throw.

Output

Note: I truncated some stack traces to make the output easier to read ("[...]").

iteration 0
iteration 100000
iteration 200000
iteration 300000
iteration 400000
iteration 500000
iteration 600000
iteration 700000
iteration 800000
iteration 900000
iteration 1000000
iteration 1100000
iteration 1200000
iteration 1300000
iteration 1400000
iteration 1500000
Ouch: java.lang.OutOfMemoryError: Java heap space; hash: 1069480624
Keep on trying...
java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Unknown Source)
    at java.util.Arrays.copyOf(Unknown Source)
    at java.util.ArrayList.ensureCapacity(Unknown Source)
    at java.util.ArrayList.add(Unknown Source)
    at testsl.Div.gobbleUpMemory(Div.java:23)
    at testsl.Div.exhaustMemory(Div.java:12)
    at testsl.Div.main(Div.java:7)
java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Unknown Source)
[...]
Ouch: java.lang.OutOfMemoryError: Java heap space; hash: 616699029
Keep on trying...
java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Unknown Source)
[...]
Ouch: java.lang.OutOfMemoryError: Java heap space; hash: 2136955031
Keep on trying...
java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Unknown Source)
[...]
Ouch: java.lang.OutOfMemoryError: Java heap space; hash: 1535562945
Keep on trying...
java.lang.OutOfMemoryError: Java heap space
Ouch: java.lang.OutOfMemoryError: Java heap space; hash: 1734048134
Keep on trying...
Ouch: java.lang.OutOfMemoryError: Java heap space; hash: 1734048134
Keep on trying...
java.lang.OutOfMemoryError: Java heap space
Ouch: java.lang.OutOfMemoryError: Java heap space; hash: 1734048134
Keep on trying...
[...]

The program

public class Div{
    static java.util.List<String> list = new java.util.ArrayList<String>();

    public static void main(String[] args) {
        exhaustMemory();
    }

    private static void exhaustMemory() {
        try {
            gobbleUpMemory();
        } catch (OutOfMemoryError e) {
            System.out.println("Ouch: " + e+"; hash: "+e.hashCode());
            e.printStackTrace();
            System.out.println("Keep on trying...");
            exhaustMemory();
        }
    }

    private static void gobbleUpMemory() {
        for (int i = 0; i < 10000000; i++) {
            list.add(new String("some random long string; use constructor to force new instance"));
            if (i % 10000000== 0) {
                System.out.println("iteration "+i);
            }
        }

    }
}
sleske
  • 81,358
  • 34
  • 189
  • 227
  • When push comes to shove, it can't allocate memory for OOME, so it flushes the ones already created. – Buhake Sindi Feb 14 '12 at 08:59
  • 1
    Minor note: some of your output seems to be out of sequence, presumably because you're printing to `System.out` but `printStackTrace()` uses `System.err` by default. You'd probably get better results by using either stream consistently. – Ilmari Karonen Feb 14 '12 at 11:59
  • @IlmariKaronen: Yes, I noticed that. It's only an example, so it didn't matter. Obviously you wouldn't use it in production code. – sleske Feb 14 '12 at 12:57
  • True, it just took me a while to figure out what the **** was going on when I first looked at the output. – Ilmari Karonen Feb 14 '12 at 12:58
6

I am pretty sure, the JVM will make absolutely sure that it has at least enough memory to throw an exception before it runs out of memory.

Oscar Gomez
  • 18,436
  • 13
  • 85
  • 118
  • 1
    But they would hit this situation no matter how much memory is reserved: http://stackoverflow.com/questions/9261705/what-happens-when-theres-insufficient-memory-to-throw-an-outofmemory#comment-11672166 – Pacerier Feb 13 '12 at 14:06
4

You seem to be confusing the virtual memory reserved by the JVM in which the JVM runs Java programs with the host OS's native memory in which the JVM is run as a native process. The JVM on your machine is running in the memory managed by the OS, not in the memory the JVM has reserved to run Java programs.

Further reading:

And as a final note, trying to catch a java.lang.Error (and its descendant classes) in order to print a stacktrace may not give you any useful information. You want a heap dump instead.

4

Exceptions indicating an attempt to violate the boundaries of a managed-memory environment are handled by the runtime of said environment, in this case the JVM. The JVM is its own process, which is running your application's IL. Should a program attempt to make a call that extends the call stack beyond the limits, or allocate more memory than the JVM can reserve, the runtime itself will inject an exception, which will cause the call stack to be unwound. Regardless of the amount of memory your program currently needs, or how deep its call stack, the JVM will have allocated enough memory within its own process bounds to create said exception and inject it into your code.

KeithS
  • 70,210
  • 21
  • 112
  • 164
  • "the JVM will have allocated enough memory within its own process bounds to create said exception" but if your code retains a reference to that exception, so it can not be reused, how can it create another? Or are you suggesting it has a special Singleton OOME object? – Raedwald Feb 15 '12 at 13:13
  • I'm not suggesting that. If your program traps and hangs on to every exception that's ever created, including ones created and injected by the JVM or OS, then eventually the JVM itself will exceed some boundary set by the OS, and the OS will shut it down for a GPF or similar error. However, that's bad design in the first place; exceptions should either be handled and then go out of scope, or be thrown out. And you should NEVER try to catch and continue on an SOE or OOME; other than "cleaning up" so you can exit gracefully, there's nothing you can do to continue execution in those situations. – KeithS Feb 15 '12 at 15:21
  • "that's bad design in the first place": terrible design. But pedantically, would the **JVM** be conforming to the specification if it failed in that manner? – Raedwald Feb 15 '12 at 15:29
4

To further clarify @Graham Borland's answer, functionally, the JVM does this at startup:

private static final OutOfMemoryError OOME = new OutOfMemoryError();

Later, the JVM executes one of the following Java bytecodes: 'new', 'anewarray', or 'multianewarray'. This instruction causes the JVM to perform a number of steps in an out of memory condition:

  1. Invoke a native function, say allocate(). allocate() attempts to allocate memory for some a new instance of a particular class or array.
  2. That allocation request fails, so the JVM invokes another native function, say doGC(), which attempts to do garbage collection.
  3. When that function returns, allocate() tries to allocate memory for the instance once again.
  4. If that fails(*), then the JVM, within allocate(), simply does a throw OOME;, referring to the OOME that it instantiated at startup. Note that it did not have to allocate that OOME, it just refers to it.

Obviously, these are not literal steps; they'll vary from JVM to JVM in implementation, but this is the high-level idea.

(*) A significant amount of work happens here before failing. The JVM will attempt to clear SoftReference objects, attempt allocation directly into the tenured generation when using a generational collector, and possibly other things, like finalization.

ahawtho
  • 704
  • 7
  • 8
3

The answers that say that the JVM will pre-allocate OutOfMemoryErrors are indeed correct.
In addition to testing this by provoking an out-of-memory situation we can just check the heap of any JVM (I used a small program that just does a sleep, running it using Oracle's Hotspot JVM from Java 8 update 31).

Using jmap we see that there seems to be 9 instances of OutOfMemoryError (even though we have plenty of memory):

> jmap -histo 12103 | grep OutOfMemoryError
 71:             9            288  java.lang.OutOfMemoryError
170:             1             32  [Ljava.lang.OutOfMemoryError;

We can then generate a heap dump:

> jmap -dump:format=b,file=heap.hprof 12315

and open it using Eclipse Memory Analyzer, where an OQL query shows that the JVM actually seems to pre-allocate OutOfMemoryErrors for all possible messages:

enter image description here

The code for the Java 8 Hotspot JVM that actually preallocates these can be found here, and looks like this (with some parts omitted):

...
// Setup preallocated OutOfMemoryError errors
k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_OutOfMemoryError(), true, CHECK_false);
k_h = instanceKlassHandle(THREAD, k);
Universe::_out_of_memory_error_java_heap = k_h->allocate_instance(CHECK_false);
Universe::_out_of_memory_error_metaspace = k_h->allocate_instance(CHECK_false);
Universe::_out_of_memory_error_class_metaspace = k_h->allocate_instance(CHECK_false);
Universe::_out_of_memory_error_array_size = k_h->allocate_instance(CHECK_false);
Universe::_out_of_memory_error_gc_overhead_limit =
  k_h->allocate_instance(CHECK_false);

...

if (!DumpSharedSpaces) {
  // These are the only Java fields that are currently set during shared space dumping.
  // We prefer to not handle this generally, so we always reinitialize these detail messages.
  Handle msg = java_lang_String::create_from_str("Java heap space", CHECK_false);
  java_lang_Throwable::set_message(Universe::_out_of_memory_error_java_heap, msg());

  msg = java_lang_String::create_from_str("Metaspace", CHECK_false);
  java_lang_Throwable::set_message(Universe::_out_of_memory_error_metaspace, msg());
  msg = java_lang_String::create_from_str("Compressed class space", CHECK_false);
  java_lang_Throwable::set_message(Universe::_out_of_memory_error_class_metaspace, msg());

  msg = java_lang_String::create_from_str("Requested array size exceeds VM limit", CHECK_false);
  java_lang_Throwable::set_message(Universe::_out_of_memory_error_array_size, msg());

  msg = java_lang_String::create_from_str("GC overhead limit exceeded", CHECK_false);
  java_lang_Throwable::set_message(Universe::_out_of_memory_error_gc_overhead_limit, msg());

  msg = java_lang_String::create_from_str("/ by zero", CHECK_false);
  java_lang_Throwable::set_message(Universe::_arithmetic_exception_instance, msg());

  // Setup the array of errors that have preallocated backtrace
  k = Universe::_out_of_memory_error_java_heap->klass();
  assert(k->name() == vmSymbols::java_lang_OutOfMemoryError(), "should be out of memory error");
  k_h = instanceKlassHandle(THREAD, k);

  int len = (StackTraceInThrowable) ? (int)PreallocatedOutOfMemoryErrorCount : 0;
  Universe::_preallocated_out_of_memory_error_array = oopFactory::new_objArray(k_h(), len, CHECK_false);
  for (int i=0; i<len; i++) {
    oop err = k_h->allocate_instance(CHECK_false);
    Handle err_h = Handle(THREAD, err);
    java_lang_Throwable::allocate_backtrace(err_h, CHECK_false);
    Universe::preallocated_out_of_memory_errors()->obj_at_put(i, err_h());
  }
  Universe::_preallocated_out_of_memory_error_avail_count = (jint)len;
}
...

and this code shows that the JVM will first try to use one of the pre-allocated errors with space for a stack trace, and then fall back to one without a stack trace:

oop Universe::gen_out_of_memory_error(oop default_err) {
  // generate an out of memory error:
  // - if there is a preallocated error with backtrace available then return it wth
  //   a filled in stack trace.
  // - if there are no preallocated errors with backtrace available then return
  //   an error without backtrace.
  int next;
  if (_preallocated_out_of_memory_error_avail_count > 0) {
    next = (int)Atomic::add(-1, &_preallocated_out_of_memory_error_avail_count);
    assert(next < (int)PreallocatedOutOfMemoryErrorCount, "avail count is corrupt");
  } else {
    next = -1;
  }
  if (next < 0) {
    // all preallocated errors have been used.
    // return default
    return default_err;
  } else {
    // get the error object at the slot and set set it to NULL so that the
    // array isn't keeping it alive anymore.
    oop exc = preallocated_out_of_memory_errors()->obj_at(next);
    assert(exc != NULL, "slot has been used already");
    preallocated_out_of_memory_errors()->obj_at_put(next, NULL);

    // use the message from the default error
    oop msg = java_lang_Throwable::message(default_err);
    assert(msg != NULL, "no message");
    java_lang_Throwable::set_message(exc, msg);

    // populate the stack trace and return it.
    java_lang_Throwable::fill_in_stack_trace_of_preallocated_backtrace(exc);
    return exc;
  }
}
Johan Kaving
  • 4,870
  • 1
  • 27
  • 21
  • Good post, I'll accept this as answer for a week to give it more visibility before reverting back to the previous answer. – Pacerier May 24 '15 at 21:44
  • In Java 8 and higher, the Permanent Generation Space has been **removed completely** and you can no longer specify heap space allocation memory size from Java 8 and higher since they've introduced dynamic class metadata memory management called `Metaspace`. It'll be nice if you could show a piece of code that caters also for PermGen and compare it with Metaspace as well. – Buhake Sindi May 25 '15 at 12:58
  • @BuhakeSindi - I don't see what the Permanent Generation has to do with this. New objects are not allocated in the Permanent Generation as you state in your answer. You also never mention the fact that OutOfMemoryErrors are pre-allocated (which is the actual answer to the question). – Johan Kaving May 26 '15 at 11:20
  • 1
    Ok, what I am saying is that from Java 8, object allocation are computed dynamically whereas before it was allocated on a predefined heap space, hence perhaps it's pre-allocated beforehand. Even though OOME are pre-allocated, there is "computation" done to determine whether the OOME needs to be thrown (hence why I put reference to the JLS specification). – Buhake Sindi May 26 '15 at 11:26
  • @Pacerier - thanks. I would suggest changing the accepted answer to one of the ones mentioning pre-allocated OutOfMemoryErrors. – Johan Kaving May 26 '15 at 11:28
  • 1
    The Java heap size is just as predefined in Java 8 as it was before. The Permanent Generation was part of the heap that contained class meta-data, interned strings and class statics. It had a limited size that needed to be tuned separately from the total heap size. In Java 8 the class meta-data has been moved to native memory and interned strings and class statics have been moved to the regular Java heap (see e.g. here: http://www.infoq.com/articles/Java-PERMGEN-Removed). – Johan Kaving May 26 '15 at 11:39