Ivo Mägi

Where did my OOM go?

March 24th, 2009 | by Ivo Mägi |

Editor: We have a guest appearance from a CDO of a Fortune 500 company (actually not Fortune 500, but yes, a development manager for 200 devs). The twist? He has a compiler installed and apparently an editor too.

The other day I was playing around with a tool for memory analysis and wrote a small snippet using which I would be able to test the new tool. Quickly (Editor: yeah right quickly) created the following and executed it:

import java.util.*;   
class Leak {  
  static List<Integer> list = new ArrayList<Integer>();  
  public static void main(String[] args) {  
    for (int i = 0; i >= 0 ;) {  
      list.add(i++);  
    }  
    System.out.println("I will either reach here or die trying (with OOM)");  
  }  
}

And what do you think I was displayed by my command prompt (editor: CDOs don’t have a command prompt):

Option A:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at java.util.Arrays.copyOf(Arrays.java:2760)
        at java.util.Arrays.copyOf(Arrays.java:2734)
        at java.util.ArrayList.ensureCapacity(ArrayList.java:167)
        at java.util.ArrayList.add(ArrayList.java:351)
        at Leak.main(Leak.java:6)

Option B:

I will either reach here or die trying (with OOM)

Well, as I found out, it doesn’t print out anything. As this is now two years from my last real Java development experience (got demoted to C-level), I went to my hardcore Java hackers. For 10 minutes we all stood with bedazzled faces, before it struck – the memory will be allocated in a way that there is no room for new OutOfMemoryError() to be created.

If you execute the above with 64MB heapsize (which is the default heapsize):

C:\work\snippets\leak java -Xmx64m Leak
C:\work\snippets\leak

But if you increase (well actually modify) the heap size a bit:

C:\work\snippets\leak java -Xmx65m Leak
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at java.util.Arrays.copyOf(Arrays.java:2760)
        at java.util.Arrays.copyOf(Arrays.java:2734)
        at java.util.ArrayList.ensureCapacity(ArrayList.java:167)
        at java.util.ArrayList.add(ArrayList.java:351)
        at Leak.main(Leak.java:6)
C:\work\snippets\leak

Moral of the story? I definitely would not want to be fixing a production system dying like this (Editor: lucky you, you don’t have to) – most likely I would be mad way before I could have grasped anything about the reasons …

  • Toomas Römer
    The result will depend on the system, JDK version and available memory.

    The idea behind the sample is that the heap usage is increased in such small doses that finally when there is an actual OOM it will propagate and just exit because there is not enough heap to construct the actual OOMError object.

    I was not able to reproduce this with my JDK's running on Linux with lots of ram. The ram plays a role because starting from certain versions of JDK the default heap is actually dynamic depending on the amount of ram.

    Of course the arraylist resize might not be that small and depends on the current size a lot. My JDK 1.5 shows: int newCapacity = (oldCapacity * 3)/2 + 1;

    So actually when all the planets are aligned your production system will just halt without a single warning. Bedazzled looks follow as anything could have happened :)
  • KJ
    Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.lang.Integer.valueOf(Integer.java:585)
blog comments powered by Disqus