Mercurial > hg > graal-compiler
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, ®_map, java_thread); | 1572 vframe* vf = vframe::new_vframe(&f, ®_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 } |