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, ...) |
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 } |