Blin
Blin

Reputation: 698

HeapDumpOnOutOfMemoryError works only once on periodical tasks

I have a couple of applications that run in specified intervals. To monitor OutOfMemoryError i've decided to enable HeapDumpOnOutOfMemoryError, and before doing this i decided to do some research. Some of applications have maximum heap size of 2GB, so generating multiple heap dumps in rapid succession could eat up all disk space.

I've written a small script to check how it will work.

import java.util.LinkedList;
import java.util.List;

public class Test implements Runnable{

        public static void main(String[] args) throws Exception {
                new Thread(new Test()).start();
        }

        public void run() {
                while (true) {
                        try{
                                List<Object> list = new LinkedList<Object>();
                                while (true){
                                        list.add(new Object());
                                }
                        }
                        catch (Throwable e){
                                System.out.println(e);
                        }
                        try {
                                Thread.sleep(1000);
                        }
                        catch (InterruptedException ignored) {

                        }
                }
        }
}

And here is the result

$ java -XX:+HeapDumpOnOutOfMemoryError -Xmx2M Test                                                                                                                                                        
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid25711.hprof ...
Heap dump file created [14694890 bytes in 0,101 secs]
java.lang.OutOfMemoryError: Java heap space
java.lang.OutOfMemoryError: Java heap space

It works as i would want it to, but i would like to know why.

Looking at openjdk6 source code i've found the following

void report_java_out_of_memory(const char* message) {
  static jint out_of_memory_reported = 0;

  // A number of threads may attempt to report OutOfMemoryError at around the
  // same time. To avoid dumping the heap or executing the data collection
  // commands multiple times we just do it once when the first threads reports
  // the error.
  if (Atomic::cmpxchg(1, &out_of_memory_reported, 0) == 0) {
    // create heap dump before OnOutOfMemoryError commands are executed
    if (HeapDumpOnOutOfMemoryError) {
      tty->print_cr("java.lang.OutOfMemoryError: %s", message);
      HeapDumper::dump_heap_from_oome();
    }   

    if (OnOutOfMemoryError && OnOutOfMemoryError[0]) {
      VMError err(message);
      err.report_java_out_of_memory();
    }   
  }
}

How does the first if statement work?

EDIT: it seems that heapdump should be created every time message is printed, but it does not happen. Why is that so?

Upvotes: 5

Views: 1384

Answers (1)

Michael Schmei&#223;er
Michael Schmei&#223;er

Reputation: 3417

The if statement contains a compare-and-exchange atomic operation which will return 0 if and only if the exchange was performed by the running thread. Compare-and-exchange (also known as compare-and-swap) works the following way:

  • Supply a value of which you think a variable contains (0 in your case, the variable is out_of_memory_reported)
  • Supply a value for which you would like to exchange the value (1 in your case)
  • If the value is the one you supplied, it is exchanged for the replacement value atomically (no other thread may change the value after it has been compared against your estimation) and 0 is returned
  • Otherwise, nothing happens and a value different from 0 is returned to indicate the failure

Upvotes: 3

Related Questions