comparison src/share/vm/services/heapDumper.cpp @ 1775:30f67acf635d

6765718: Indicate which thread throwing OOME when generating the heap dump at OOME Summary: Emit a fake frame that makes it look like the thread is in the OutOfMemoryError zero-parameter constructor Reviewed-by: dcubed
author thurka
date Sat, 11 Sep 2010 08:18:31 +0200
parents c18cbe5936b8
children f95d63e2154a
comparison
equal deleted inserted replaced
1774:ea175c1b79ce 1775:30f67acf635d
1 /* 1 /*
2 * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved. 2 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 * 4 *
5 * This code is free software; you can redistribute it and/or modify it 5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as 6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
1303 class VM_HeapDumper : public VM_GC_Operation { 1303 class VM_HeapDumper : public VM_GC_Operation {
1304 private: 1304 private:
1305 static VM_HeapDumper* _global_dumper; 1305 static VM_HeapDumper* _global_dumper;
1306 static DumpWriter* _global_writer; 1306 static DumpWriter* _global_writer;
1307 DumpWriter* _local_writer; 1307 DumpWriter* _local_writer;
1308 JavaThread* _oome_thread;
1309 methodOop _oome_constructor;
1308 bool _gc_before_heap_dump; 1310 bool _gc_before_heap_dump;
1309 bool _is_segmented_dump; 1311 bool _is_segmented_dump;
1310 jlong _dump_start; 1312 jlong _dump_start;
1311 GrowableArray<Klass*>* _klass_map; 1313 GrowableArray<Klass*>* _klass_map;
1312 ThreadStackTrace** _stack_traces; 1314 ThreadStackTrace** _stack_traces;
1364 // fixes up the current dump record )and writes HPROF_HEAP_DUMP_END 1366 // fixes up the current dump record )and writes HPROF_HEAP_DUMP_END
1365 // record in the case of a segmented heap dump) 1367 // record in the case of a segmented heap dump)
1366 void end_of_dump(); 1368 void end_of_dump();
1367 1369
1368 public: 1370 public:
1369 VM_HeapDumper(DumpWriter* writer, bool gc_before_heap_dump) : 1371 VM_HeapDumper(DumpWriter* writer, bool gc_before_heap_dump, bool oome) :
1370 VM_GC_Operation(0 /* total collections, dummy, ignored */, 1372 VM_GC_Operation(0 /* total collections, dummy, ignored */,
1371 0 /* total full collections, dummy, ignored */, 1373 0 /* total full collections, dummy, ignored */,
1372 gc_before_heap_dump) { 1374 gc_before_heap_dump) {
1373 _local_writer = writer; 1375 _local_writer = writer;
1374 _gc_before_heap_dump = gc_before_heap_dump; 1376 _gc_before_heap_dump = gc_before_heap_dump;
1375 _is_segmented_dump = false; 1377 _is_segmented_dump = false;
1376 _dump_start = (jlong)-1; 1378 _dump_start = (jlong)-1;
1377 _klass_map = new (ResourceObj::C_HEAP) GrowableArray<Klass*>(INITIAL_CLASS_COUNT, true); 1379 _klass_map = new (ResourceObj::C_HEAP) GrowableArray<Klass*>(INITIAL_CLASS_COUNT, true);
1378 _stack_traces = NULL; 1380 _stack_traces = NULL;
1379 _num_threads = 0; 1381 _num_threads = 0;
1382 if (oome) {
1383 assert(!Thread::current()->is_VM_thread(), "Dump from OutOfMemoryError cannot be called by the VMThread");
1384 // get OutOfMemoryError zero-parameter constructor
1385 instanceKlass* oome_ik = instanceKlass::cast(SystemDictionary::OutOfMemoryError_klass());
1386 _oome_constructor = oome_ik->find_method(vmSymbols::object_initializer_name(),
1387 vmSymbols::void_method_signature());
1388 // get thread throwing OOME when generating the heap dump at OOME
1389 _oome_thread = JavaThread::current();
1390 } else {
1391 _oome_thread = NULL;
1392 _oome_constructor = NULL;
1393 }
1380 } 1394 }
1381 ~VM_HeapDumper() { 1395 ~VM_HeapDumper() {
1382 if (_stack_traces != NULL) { 1396 if (_stack_traces != NULL) {
1383 for (int i=0; i < _num_threads; i++) { 1397 for (int i=0; i < _num_threads; i++) {
1384 delete _stack_traces[i]; 1398 delete _stack_traces[i];
1555 1569
1556 RegisterMap reg_map(java_thread); 1570 RegisterMap reg_map(java_thread);
1557 frame f = java_thread->last_frame(); 1571 frame f = java_thread->last_frame();
1558 vframe* vf = vframe::new_vframe(&f, &reg_map, java_thread); 1572 vframe* vf = vframe::new_vframe(&f, &reg_map, java_thread);
1559 frame* last_entry_frame = NULL; 1573 frame* last_entry_frame = NULL;
1560 1574 int extra_frames = 0;
1575
1576 if (java_thread == _oome_thread && _oome_constructor != NULL) {
1577 extra_frames++;
1578 }
1561 while (vf != NULL) { 1579 while (vf != NULL) {
1562 blk.set_frame_number(stack_depth); 1580 blk.set_frame_number(stack_depth);
1563 if (vf->is_java_frame()) { 1581 if (vf->is_java_frame()) {
1564 1582
1565 // java frame (interpreted, compiled, ...) 1583 // java frame (interpreted, compiled, ...)
1572 1590
1573 if (o != NULL) { 1591 if (o != NULL) {
1574 writer()->write_u1(HPROF_GC_ROOT_JAVA_FRAME); 1592 writer()->write_u1(HPROF_GC_ROOT_JAVA_FRAME);
1575 writer()->write_objectID(o); 1593 writer()->write_objectID(o);
1576 writer()->write_u4(thread_serial_num); 1594 writer()->write_u4(thread_serial_num);
1577 writer()->write_u4((u4) stack_depth); 1595 writer()->write_u4((u4) (stack_depth + extra_frames));
1578 } 1596 }
1579 } 1597 }
1580 } 1598 }
1581 } else { 1599 } else {
1582 // native frame 1600 // native frame
1762 _stack_traces[_num_threads++] = stack_trace; 1780 _stack_traces[_num_threads++] = stack_trace;
1763 1781
1764 // write HPROF_FRAME records for this thread's stack trace 1782 // write HPROF_FRAME records for this thread's stack trace
1765 int depth = stack_trace->get_stack_depth(); 1783 int depth = stack_trace->get_stack_depth();
1766 int thread_frame_start = frame_serial_num; 1784 int thread_frame_start = frame_serial_num;
1785 int extra_frames = 0;
1786 // write fake frame that makes it look like the thread, which caused OOME,
1787 // is in the OutOfMemoryError zero-parameter constructor
1788 if (thread == _oome_thread && _oome_constructor != NULL) {
1789 int oome_serial_num = _klass_map->find(Klass::cast(_oome_constructor->method_holder()));
1790 // the class serial number starts from 1
1791 assert(oome_serial_num > 0, "OutOfMemoryError class not found");
1792 DumperSupport::dump_stack_frame(writer(), ++frame_serial_num, oome_serial_num,
1793 _oome_constructor, 0);
1794 extra_frames++;
1795 }
1767 for (int j=0; j < depth; j++) { 1796 for (int j=0; j < depth; j++) {
1768 StackFrameInfo* frame = stack_trace->stack_frame_at(j); 1797 StackFrameInfo* frame = stack_trace->stack_frame_at(j);
1769 methodOop m = frame->method(); 1798 methodOop m = frame->method();
1770 int class_serial_num = _klass_map->find(Klass::cast(m->method_holder())); 1799 int class_serial_num = _klass_map->find(Klass::cast(m->method_holder()));
1771 // the class serial number starts from 1 1800 // the class serial number starts from 1
1772 assert(class_serial_num > 0, "class not found"); 1801 assert(class_serial_num > 0, "class not found");
1773 DumperSupport::dump_stack_frame(writer(), ++frame_serial_num, class_serial_num, m, frame->bci()); 1802 DumperSupport::dump_stack_frame(writer(), ++frame_serial_num, class_serial_num, m, frame->bci());
1774 } 1803 }
1804 depth += extra_frames;
1775 1805
1776 // write HPROF_TRACE record for one thread 1806 // write HPROF_TRACE record for one thread
1777 DumperSupport::write_header(writer(), HPROF_TRACE, 3*sizeof(u4) + depth*oopSize); 1807 DumperSupport::write_header(writer(), HPROF_TRACE, 3*sizeof(u4) + depth*oopSize);
1778 int stack_serial_num = _num_threads + STACK_TRACE_ID; 1808 int stack_serial_num = _num_threads + STACK_TRACE_ID;
1779 writer()->write_u4(stack_serial_num); // stack trace serial number 1809 writer()->write_u4(stack_serial_num); // stack trace serial number
1806 } 1836 }
1807 return -1; 1837 return -1;
1808 } 1838 }
1809 1839
1810 // generate the dump 1840 // generate the dump
1811 VM_HeapDumper dumper(&writer, _gc_before_heap_dump); 1841 VM_HeapDumper dumper(&writer, _gc_before_heap_dump, _oome);
1812 if (Thread::current()->is_VM_thread()) { 1842 if (Thread::current()->is_VM_thread()) {
1813 assert(SafepointSynchronize::is_at_safepoint(), "Expected to be called at a safepoint"); 1843 assert(SafepointSynchronize::is_at_safepoint(), "Expected to be called at a safepoint");
1814 dumper.doit(); 1844 dumper.doit();
1815 } else { 1845 } else {
1816 VMThread::execute(&dumper); 1846 VMThread::execute(&dumper);
1867 _error = os::strdup(error); 1897 _error = os::strdup(error);
1868 assert(_error != NULL, "allocation failure"); 1898 assert(_error != NULL, "allocation failure");
1869 } 1899 }
1870 } 1900 }
1871 1901
1902 // Called by out-of-memory error reporting by a single Java thread
1903 // outside of a JVM safepoint
1904 void HeapDumper::dump_heap_from_oome() {
1905 HeapDumper::dump_heap(true);
1906 }
1907
1872 // Called by error reporting by a single Java thread outside of a JVM safepoint, 1908 // Called by error reporting by a single Java thread outside of a JVM safepoint,
1873 // or by heap dumping by the VM thread during a (GC) safepoint. Thus, these various 1909 // or by heap dumping by the VM thread during a (GC) safepoint. Thus, these various
1874 // callers are strictly serialized and guaranteed not to interfere below. For more 1910 // callers are strictly serialized and guaranteed not to interfere below. For more
1875 // general use, however, this method will need modification to prevent 1911 // general use, however, this method will need modification to prevent
1876 // inteference when updating the static variables base_path and dump_file_seq below. 1912 // inteference when updating the static variables base_path and dump_file_seq below.
1877 void HeapDumper::dump_heap() { 1913 void HeapDumper::dump_heap() {
1914 HeapDumper::dump_heap(false);
1915 }
1916
1917 void HeapDumper::dump_heap(bool oome) {
1878 static char base_path[JVM_MAXPATHLEN] = {'\0'}; 1918 static char base_path[JVM_MAXPATHLEN] = {'\0'};
1879 static uint dump_file_seq = 0; 1919 static uint dump_file_seq = 0;
1880 char my_path[JVM_MAXPATHLEN] = {'\0'}; 1920 char my_path[JVM_MAXPATHLEN] = {'\0'};
1881 1921
1882 // The dump file defaults to java_pid<pid>.hprof in the current working 1922 // The dump file defaults to java_pid<pid>.hprof in the current working
1928 strcat(my_path, fn); 1968 strcat(my_path, fn);
1929 } 1969 }
1930 dump_file_seq++; // increment seq number for next time we dump 1970 dump_file_seq++; // increment seq number for next time we dump
1931 1971
1932 HeapDumper dumper(false /* no GC before heap dump */, 1972 HeapDumper dumper(false /* no GC before heap dump */,
1933 true /* send to tty */); 1973 true /* send to tty */,
1974 oome /* pass along out-of-memory-error flag */);
1934 dumper.dump(my_path); 1975 dumper.dump(my_path);
1935 } 1976 }