HeapDumpOnOutOfMemoryError仅对定期任务起作用一次

时间:2012-07-13 11:07:58

标签: java out-of-memory

我有几个以指定的时间间隔运行的应用程序。为了监控OutOfMemoryError,我决定启用HeapDumpOnOutOfMemoryError,在此之前,我决定做一些研究。某些应用程序的最大堆大小为2GB,因此快速连续生成多个堆转储会占用所有磁盘空间。

我写了一个小脚本来检查它是如何工作的。

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) {

                        }
                }
        }
}

这是结果

$ 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

它可以像我希望的那样工作,但我想知道原因。

查看openjdk6源代码我发现了以下内容

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();
    }   
  }
}

第一个if语句如何工作?

编辑:似乎每次打印消息时都应创建heapdump,但不会发生。为什么会这样?

1 个答案:

答案 0 :(得分:3)

if语句包含比较和交换原子操作,当且仅当交换是由正在运行的线程执行时才会返回0。比较和交换(也称为比较和交换)以下列方式工作:

  • 提供您认为变量包含的值(在您的情况下为0,变量为out_of_memory_reported)
  • 提供您想要交换价值的值(在您的情况下为1)
  • 如果值是您提供的值,则将其替换为替换值原子(在与您的估算进行比较后,其他任何线程都不会更改该值)并返回0
  • 否则,没有任何反应,返回不同于0的值表示失败