src/share/vm/services/heapDumper.cpp

changeset 831
4d05b7cb7842
parent 791
1ee8caae33af
child 952
e9be0e04635a
equal deleted inserted replaced
827:05366dad12cf 831:4d05b7cb7842
341 HPROF_GC_PRIM_ARRAY_DUMP = 0x23 341 HPROF_GC_PRIM_ARRAY_DUMP = 0x23
342 } hprofTag; 342 } hprofTag;
343 343
344 // Default stack trace ID (used for dummy HPROF_TRACE record) 344 // Default stack trace ID (used for dummy HPROF_TRACE record)
345 enum { 345 enum {
346 STACK_TRACE_ID = 1 346 STACK_TRACE_ID = 1,
347 INITIAL_CLASS_COUNT = 200
347 }; 348 };
348 349
349 350
350 // Supports I/O operations on a dump file 351 // Supports I/O operations on a dump file
351 352
406 void write_u2(u2 x); 407 void write_u2(u2 x);
407 void write_u4(u4 x); 408 void write_u4(u4 x);
408 void write_u8(u8 x); 409 void write_u8(u8 x);
409 void write_objectID(oop o); 410 void write_objectID(oop o);
410 void write_classID(Klass* k); 411 void write_classID(Klass* k);
412 void write_id(u4 x);
411 }; 413 };
412 414
413 DumpWriter::DumpWriter(const char* path) { 415 DumpWriter::DumpWriter(const char* path) {
414 // try to allocate an I/O buffer of io_buffer_size. If there isn't 416 // try to allocate an I/O buffer of io_buffer_size. If there isn't
415 // sufficient memory then reduce size until we can allocate something. 417 // sufficient memory then reduce size until we can allocate something.
543 address a = (address)((uintptr_t)o); 545 address a = (address)((uintptr_t)o);
544 #ifdef _LP64 546 #ifdef _LP64
545 write_u8((u8)a); 547 write_u8((u8)a);
546 #else 548 #else
547 write_u4((u4)a); 549 write_u4((u4)a);
550 #endif
551 }
552
553 void DumpWriter::write_id(u4 x) {
554 #ifdef _LP64
555 write_u8((u8) x);
556 #else
557 write_u4(x);
548 #endif 558 #endif
549 } 559 }
550 560
551 // We use java mirror as the class ID 561 // We use java mirror as the class ID
552 void DumpWriter::write_classID(Klass* k) { 562 void DumpWriter::write_classID(Klass* k) {
594 604
595 // creates HPROF_GC_OBJ_ARRAY_DUMP record for the given object array 605 // creates HPROF_GC_OBJ_ARRAY_DUMP record for the given object array
596 static void dump_object_array(DumpWriter* writer, objArrayOop array); 606 static void dump_object_array(DumpWriter* writer, objArrayOop array);
597 // creates HPROF_GC_PRIM_ARRAY_DUMP record for the given type array 607 // creates HPROF_GC_PRIM_ARRAY_DUMP record for the given type array
598 static void dump_prim_array(DumpWriter* writer, typeArrayOop array); 608 static void dump_prim_array(DumpWriter* writer, typeArrayOop array);
609 // create HPROF_FRAME record for the given method and bci
610 static void dump_stack_frame(DumpWriter* writer, int frame_serial_num, int class_serial_num, methodOop m, int bci);
599 }; 611 };
600 612
601 // write a header of the given type 613 // write a header of the given type
602 void DumperSupport:: write_header(DumpWriter* writer, hprofTag tag, u4 len) { 614 void DumperSupport:: write_header(DumpWriter* writer, hprofTag tag, u4 len) {
603 writer->write_u1((u1)tag); 615 writer->write_u1((u1)tag);
1068 } 1080 }
1069 default : ShouldNotReachHere(); 1081 default : ShouldNotReachHere();
1070 } 1082 }
1071 } 1083 }
1072 1084
1085 // create a HPROF_FRAME record of the given methodOop and bci
1086 void DumperSupport::dump_stack_frame(DumpWriter* writer,
1087 int frame_serial_num,
1088 int class_serial_num,
1089 methodOop m,
1090 int bci) {
1091 int line_number;
1092 if (m->is_native()) {
1093 line_number = -3; // native frame
1094 } else {
1095 line_number = m->line_number_from_bci(bci);
1096 }
1097
1098 write_header(writer, HPROF_FRAME, 4*oopSize + 2*sizeof(u4));
1099 writer->write_id(frame_serial_num); // frame serial number
1100 writer->write_objectID(m->name()); // method's name
1101 writer->write_objectID(m->signature()); // method's signature
1102
1103 assert(Klass::cast(m->method_holder())->oop_is_instance(), "not instanceKlass");
1104 writer->write_objectID(instanceKlass::cast(m->method_holder())->source_file_name()); // source file name
1105 writer->write_u4(class_serial_num); // class serial number
1106 writer->write_u4((u4) line_number); // line number
1107 }
1073 1108
1074 // Support class used to generate HPROF_UTF8 records from the entries in the 1109 // Support class used to generate HPROF_UTF8 records from the entries in the
1075 // SymbolTable. 1110 // SymbolTable.
1076 1111
1077 class SymbolTableDumper : public OopClosure { 1112 class SymbolTableDumper : public OopClosure {
1102 1137
1103 class JNILocalsDumper : public OopClosure { 1138 class JNILocalsDumper : public OopClosure {
1104 private: 1139 private:
1105 DumpWriter* _writer; 1140 DumpWriter* _writer;
1106 u4 _thread_serial_num; 1141 u4 _thread_serial_num;
1142 int _frame_num;
1107 DumpWriter* writer() const { return _writer; } 1143 DumpWriter* writer() const { return _writer; }
1108 public: 1144 public:
1109 JNILocalsDumper(DumpWriter* writer, u4 thread_serial_num) { 1145 JNILocalsDumper(DumpWriter* writer, u4 thread_serial_num) {
1110 _writer = writer; 1146 _writer = writer;
1111 _thread_serial_num = thread_serial_num; 1147 _thread_serial_num = thread_serial_num;
1112 } 1148 _frame_num = -1; // default - empty stack
1149 }
1150 void set_frame_number(int n) { _frame_num = n; }
1113 void do_oop(oop* obj_p); 1151 void do_oop(oop* obj_p);
1114 void do_oop(narrowOop* obj_p) { ShouldNotReachHere(); } 1152 void do_oop(narrowOop* obj_p) { ShouldNotReachHere(); }
1115 }; 1153 };
1116 1154
1117 1155
1120 oop o = *obj_p; 1158 oop o = *obj_p;
1121 if (o != NULL && o != JNIHandles::deleted_handle()) { 1159 if (o != NULL && o != JNIHandles::deleted_handle()) {
1122 writer()->write_u1(HPROF_GC_ROOT_JNI_LOCAL); 1160 writer()->write_u1(HPROF_GC_ROOT_JNI_LOCAL);
1123 writer()->write_objectID(o); 1161 writer()->write_objectID(o);
1124 writer()->write_u4(_thread_serial_num); 1162 writer()->write_u4(_thread_serial_num);
1125 writer()->write_u4((u4)-1); // empty 1163 writer()->write_u4((u4)_frame_num);
1126 } 1164 }
1127 } 1165 }
1128 1166
1129 1167
1130 // Support class used to generate HPROF_GC_ROOT_JNI_GLOBAL records 1168 // Support class used to generate HPROF_GC_ROOT_JNI_GLOBAL records
1267 private: 1305 private:
1268 DumpWriter* _writer; 1306 DumpWriter* _writer;
1269 bool _gc_before_heap_dump; 1307 bool _gc_before_heap_dump;
1270 bool _is_segmented_dump; 1308 bool _is_segmented_dump;
1271 jlong _dump_start; 1309 jlong _dump_start;
1310 GrowableArray<Klass*>* _klass_map;
1311 ThreadStackTrace** _stack_traces;
1312 int _num_threads;
1272 1313
1273 // accessors 1314 // accessors
1274 DumpWriter* writer() const { return _writer; } 1315 DumpWriter* writer() const { return _writer; }
1275 bool is_segmented_dump() const { return _is_segmented_dump; } 1316 bool is_segmented_dump() const { return _is_segmented_dump; }
1276 void set_segmented_dump() { _is_segmented_dump = true; } 1317 void set_segmented_dump() { _is_segmented_dump = true; }
1289 // writes a HPROF_GC_CLASS_DUMP records for a given basic type 1330 // writes a HPROF_GC_CLASS_DUMP records for a given basic type
1290 // array (and each multi-dimensional array too) 1331 // array (and each multi-dimensional array too)
1291 static void do_basic_type_array_class_dump(klassOop k); 1332 static void do_basic_type_array_class_dump(klassOop k);
1292 1333
1293 // HPROF_GC_ROOT_THREAD_OBJ records 1334 // HPROF_GC_ROOT_THREAD_OBJ records
1294 void do_thread(JavaThread* thread, u4 thread_serial_num); 1335 int do_thread(JavaThread* thread, u4 thread_serial_num);
1295 void do_threads(); 1336 void do_threads();
1337
1338 void add_class_serial_number(Klass* k, int serial_num) {
1339 _klass_map->at_put_grow(serial_num, k);
1340 }
1341
1342 // HPROF_TRACE and HPROF_FRAME records
1343 void dump_stack_traces();
1296 1344
1297 // writes a HPROF_HEAP_DUMP or HPROF_HEAP_DUMP_SEGMENT record 1345 // writes a HPROF_HEAP_DUMP or HPROF_HEAP_DUMP_SEGMENT record
1298 void write_dump_header(); 1346 void write_dump_header();
1299 1347
1300 // fixes up the length of the current dump record 1348 // fixes up the length of the current dump record
1311 gc_before_heap_dump) { 1359 gc_before_heap_dump) {
1312 _writer = writer; 1360 _writer = writer;
1313 _gc_before_heap_dump = gc_before_heap_dump; 1361 _gc_before_heap_dump = gc_before_heap_dump;
1314 _is_segmented_dump = false; 1362 _is_segmented_dump = false;
1315 _dump_start = (jlong)-1; 1363 _dump_start = (jlong)-1;
1364 _klass_map = new (ResourceObj::C_HEAP) GrowableArray<Klass*>(INITIAL_CLASS_COUNT, true);
1365 _stack_traces = NULL;
1366 _num_threads = 0;
1367 }
1368 ~VM_HeapDumper() {
1369 if (_stack_traces != NULL) {
1370 for (int i=0; i < _num_threads; i++) {
1371 delete _stack_traces[i];
1372 }
1373 FREE_C_HEAP_ARRAY(ThreadStackTrace*, _stack_traces);
1374 }
1375 delete _klass_map;
1316 } 1376 }
1317 1377
1318 VMOp_Type type() const { return VMOp_HeapDumper; } 1378 VMOp_Type type() const { return VMOp_HeapDumper; }
1319 // used to mark sub-record boundary 1379 // used to mark sub-record boundary
1320 void check_segment_length(); 1380 void check_segment_length();
1434 1494
1435 // class ID 1495 // class ID
1436 Klass* klass = Klass::cast(k); 1496 Klass* klass = Klass::cast(k);
1437 writer->write_classID(klass); 1497 writer->write_classID(klass);
1438 1498
1499 // add the klassOop and class serial number pair
1500 dumper->add_class_serial_number(klass, class_serial_num);
1501
1439 writer->write_u4(STACK_TRACE_ID); 1502 writer->write_u4(STACK_TRACE_ID);
1440 1503
1441 // class name ID 1504 // class name ID
1442 symbolOop name = klass->name(); 1505 symbolOop name = klass->name();
1443 writer->write_objectID(name); 1506 writer->write_objectID(name);
1463 } 1526 }
1464 1527
1465 // Walk the stack of the given thread. 1528 // Walk the stack of the given thread.
1466 // Dumps a HPROF_GC_ROOT_JAVA_FRAME record for each local 1529 // Dumps a HPROF_GC_ROOT_JAVA_FRAME record for each local
1467 // Dumps a HPROF_GC_ROOT_JNI_LOCAL record for each JNI local 1530 // Dumps a HPROF_GC_ROOT_JNI_LOCAL record for each JNI local
1468 void VM_HeapDumper::do_thread(JavaThread* java_thread, u4 thread_serial_num) { 1531 //
1532 // It returns the number of Java frames in this thread stack
1533 int VM_HeapDumper::do_thread(JavaThread* java_thread, u4 thread_serial_num) {
1469 JNILocalsDumper blk(writer(), thread_serial_num); 1534 JNILocalsDumper blk(writer(), thread_serial_num);
1470 1535
1471 oop threadObj = java_thread->threadObj(); 1536 oop threadObj = java_thread->threadObj();
1472 assert(threadObj != NULL, "sanity check"); 1537 assert(threadObj != NULL, "sanity check");
1473 1538
1474 // JNI locals for the top frame 1539 int stack_depth = 0;
1475 java_thread->active_handles()->oops_do(&blk);
1476
1477 if (java_thread->has_last_Java_frame()) { 1540 if (java_thread->has_last_Java_frame()) {
1478 1541
1479 // vframes are resource allocated 1542 // vframes are resource allocated
1480 Thread* current_thread = Thread::current(); 1543 Thread* current_thread = Thread::current();
1481 ResourceMark rm(current_thread); 1544 ResourceMark rm(current_thread);
1482 HandleMark hm(current_thread); 1545 HandleMark hm(current_thread);
1483 1546
1484 RegisterMap reg_map(java_thread); 1547 RegisterMap reg_map(java_thread);
1485 frame f = java_thread->last_frame(); 1548 frame f = java_thread->last_frame();
1486 vframe* vf = vframe::new_vframe(&f, &reg_map, java_thread); 1549 vframe* vf = vframe::new_vframe(&f, &reg_map, java_thread);
1550 frame* last_entry_frame = NULL;
1487 1551
1488 while (vf != NULL) { 1552 while (vf != NULL) {
1553 blk.set_frame_number(stack_depth);
1489 if (vf->is_java_frame()) { 1554 if (vf->is_java_frame()) {
1490 1555
1491 // java frame (interpreted, compiled, ...) 1556 // java frame (interpreted, compiled, ...)
1492 javaVFrame *jvf = javaVFrame::cast(vf); 1557 javaVFrame *jvf = javaVFrame::cast(vf);
1493
1494 if (!(jvf->method()->is_native())) { 1558 if (!(jvf->method()->is_native())) {
1495 StackValueCollection* locals = jvf->locals(); 1559 StackValueCollection* locals = jvf->locals();
1496 for (int slot=0; slot<locals->size(); slot++) { 1560 for (int slot=0; slot<locals->size(); slot++) {
1497 if (locals->at(slot)->type() == T_OBJECT) { 1561 if (locals->at(slot)->type() == T_OBJECT) {
1498 oop o = locals->obj_at(slot)(); 1562 oop o = locals->obj_at(slot)();
1499 1563
1500 if (o != NULL) { 1564 if (o != NULL) {
1501 writer()->write_u1(HPROF_GC_ROOT_JAVA_FRAME); 1565 writer()->write_u1(HPROF_GC_ROOT_JAVA_FRAME);
1502 writer()->write_objectID(o); 1566 writer()->write_objectID(o);
1503 writer()->write_u4(thread_serial_num); 1567 writer()->write_u4(thread_serial_num);
1504 writer()->write_u4((u4)-1); // empty 1568 writer()->write_u4((u4) stack_depth);
1505 } 1569 }
1506 } 1570 }
1507 } 1571 }
1572 } else {
1573 // native frame
1574 if (stack_depth == 0) {
1575 // JNI locals for the top frame.
1576 java_thread->active_handles()->oops_do(&blk);
1577 } else {
1578 if (last_entry_frame != NULL) {
1579 // JNI locals for the entry frame
1580 assert(last_entry_frame->is_entry_frame(), "checking");
1581 last_entry_frame->entry_frame_call_wrapper()->handles()->oops_do(&blk);
1582 }
1583 }
1508 } 1584 }
1585 // increment only for Java frames
1586 stack_depth++;
1587 last_entry_frame = NULL;
1588
1509 } else { 1589 } else {
1510
1511 // externalVFrame - if it's an entry frame then report any JNI locals 1590 // externalVFrame - if it's an entry frame then report any JNI locals
1512 // as roots 1591 // as roots when we find the corresponding native javaVFrame
1513 frame* fr = vf->frame_pointer(); 1592 frame* fr = vf->frame_pointer();
1514 assert(fr != NULL, "sanity check"); 1593 assert(fr != NULL, "sanity check");
1515 if (fr->is_entry_frame()) { 1594 if (fr->is_entry_frame()) {
1516 fr->entry_frame_call_wrapper()->handles()->oops_do(&blk); 1595 last_entry_frame = fr;
1517 } 1596 }
1518 } 1597 }
1519
1520 vf = vf->sender(); 1598 vf = vf->sender();
1521 } 1599 }
1522 } 1600 } else {
1601 // no last java frame but there may be JNI locals
1602 java_thread->active_handles()->oops_do(&blk);
1603 }
1604 return stack_depth;
1523 } 1605 }
1524 1606
1525 1607
1526 // write a HPROF_GC_ROOT_THREAD_OBJ record for each java thread. Then walk 1608 // write a HPROF_GC_ROOT_THREAD_OBJ record for each java thread. Then walk
1527 // the stack so that locals and JNI locals are dumped. 1609 // the stack so that locals and JNI locals are dumped.
1528 void VM_HeapDumper::do_threads() { 1610 void VM_HeapDumper::do_threads() {
1529 u4 thread_serial_num = 0; 1611 for (int i=0; i < _num_threads; i++) {
1530 for (JavaThread* thread = Threads::first(); thread != NULL ; thread = thread->next()) { 1612 JavaThread* thread = _stack_traces[i]->thread();
1531 oop threadObj = thread->threadObj(); 1613 oop threadObj = thread->threadObj();
1532 if (threadObj != NULL && !thread->is_exiting() && !thread->is_hidden_from_external_view()) { 1614 u4 thread_serial_num = i+1;
1533 ++thread_serial_num; 1615 u4 stack_serial_num = thread_serial_num + STACK_TRACE_ID;
1534 1616 writer()->write_u1(HPROF_GC_ROOT_THREAD_OBJ);
1535 writer()->write_u1(HPROF_GC_ROOT_THREAD_OBJ); 1617 writer()->write_objectID(threadObj);
1536 writer()->write_objectID(threadObj); 1618 writer()->write_u4(thread_serial_num); // thread number
1537 writer()->write_u4(thread_serial_num); 1619 writer()->write_u4(stack_serial_num); // stack trace serial number
1538 writer()->write_u4(STACK_TRACE_ID); 1620 int num_frames = do_thread(thread, thread_serial_num);
1539 1621 assert(num_frames == _stack_traces[i]->get_stack_depth(),
1540 do_thread(thread, thread_serial_num); 1622 "total number of Java frames not matched");
1541 }
1542 } 1623 }
1543 } 1624 }
1544 1625
1545 1626
1546 // The VM operation that dumps the heap. The dump consists of the following 1627 // The VM operation that dumps the heap. The dump consists of the following
1547 // records: 1628 // records:
1548 // 1629 //
1549 // HPROF_HEADER 1630 // HPROF_HEADER
1550 // HPROF_TRACE
1551 // [HPROF_UTF8]* 1631 // [HPROF_UTF8]*
1552 // [HPROF_LOAD_CLASS]* 1632 // [HPROF_LOAD_CLASS]*
1633 // [[HPROF_FRAME]*|HPROF_TRACE]*
1553 // [HPROF_GC_CLASS_DUMP]* 1634 // [HPROF_GC_CLASS_DUMP]*
1554 // HPROF_HEAP_DUMP 1635 // HPROF_HEAP_DUMP
1555 // 1636 //
1556 // The HPROF_TRACE record after the header is "dummy trace" record which does 1637 // The HPROF_TRACE records represent the stack traces where the heap dump
1557 // not include any frames. Other records which require a stack trace ID will 1638 // is generated and a "dummy trace" record which does not include
1558 // specify the trace ID of this record (1). It also means we can run HAT without 1639 // any frames. The dummy trace record is used to be referenced as the
1559 // needing the -stack false option. 1640 // unknown object alloc site.
1560 // 1641 //
1561 // The HPROF_HEAP_DUMP record has a length following by sub-records. To allow 1642 // The HPROF_HEAP_DUMP record has a length following by sub-records. To allow
1562 // the heap dump be generated in a single pass we remember the position of 1643 // the heap dump be generated in a single pass we remember the position of
1563 // the dump length and fix it up after all sub-records have been written. 1644 // the dump length and fix it up after all sub-records have been written.
1564 // To generate the sub-records we iterate over the heap, writing 1645 // To generate the sub-records we iterate over the heap, writing
1590 writer()->write_raw((void*)header, (int)strlen(header)); 1671 writer()->write_raw((void*)header, (int)strlen(header));
1591 writer()->write_u1(0); // terminator 1672 writer()->write_u1(0); // terminator
1592 writer()->write_u4(oopSize); 1673 writer()->write_u4(oopSize);
1593 writer()->write_u8(os::javaTimeMillis()); 1674 writer()->write_u8(os::javaTimeMillis());
1594 1675
1595 // HPROF_TRACE record without any frames
1596 DumperSupport::write_header(writer(), HPROF_TRACE, 3*sizeof(u4));
1597 writer()->write_u4(STACK_TRACE_ID);
1598 writer()->write_u4(0); // thread number
1599 writer()->write_u4(0); // frame count
1600
1601 // HPROF_UTF8 records 1676 // HPROF_UTF8 records
1602 SymbolTableDumper sym_dumper(writer()); 1677 SymbolTableDumper sym_dumper(writer());
1603 SymbolTable::oops_do(&sym_dumper); 1678 SymbolTable::oops_do(&sym_dumper);
1604 1679
1605 // write HPROF_LOAD_CLASS records 1680 // write HPROF_LOAD_CLASS records
1606 SystemDictionary::classes_do(&do_load_class); 1681 SystemDictionary::classes_do(&do_load_class);
1607 Universe::basic_type_classes_do(&do_load_class); 1682 Universe::basic_type_classes_do(&do_load_class);
1683
1684 // write HPROF_FRAME and HPROF_TRACE records
1685 // this must be called after _klass_map is built when iterating the classes above.
1686 dump_stack_traces();
1608 1687
1609 // write HPROF_HEAP_DUMP or HPROF_HEAP_DUMP_SEGMENT 1688 // write HPROF_HEAP_DUMP or HPROF_HEAP_DUMP_SEGMENT
1610 write_dump_header(); 1689 write_dump_header();
1611 1690
1612 // Writes HPROF_GC_CLASS_DUMP records 1691 // Writes HPROF_GC_CLASS_DUMP records
1644 // fixes up the length of the dump record. In the case of a segmented 1723 // fixes up the length of the dump record. In the case of a segmented
1645 // heap then the HPROF_HEAP_DUMP_END record is also written. 1724 // heap then the HPROF_HEAP_DUMP_END record is also written.
1646 end_of_dump(); 1725 end_of_dump();
1647 } 1726 }
1648 1727
1728 void VM_HeapDumper::dump_stack_traces() {
1729 // write a HPROF_TRACE record without any frames to be referenced as object alloc sites
1730 DumperSupport::write_header(writer(), HPROF_TRACE, 3*sizeof(u4));
1731 writer()->write_u4((u4) STACK_TRACE_ID);
1732 writer()->write_u4(0); // thread number
1733 writer()->write_u4(0); // frame count
1734
1735 _stack_traces = NEW_C_HEAP_ARRAY(ThreadStackTrace*, Threads::number_of_threads());
1736 int frame_serial_num = 0;
1737 for (JavaThread* thread = Threads::first(); thread != NULL ; thread = thread->next()) {
1738 oop threadObj = thread->threadObj();
1739 if (threadObj != NULL && !thread->is_exiting() && !thread->is_hidden_from_external_view()) {
1740 // dump thread stack trace
1741 ThreadStackTrace* stack_trace = new ThreadStackTrace(thread, false);
1742 stack_trace->dump_stack_at_safepoint(-1);
1743 _stack_traces[_num_threads++] = stack_trace;
1744
1745 // write HPROF_FRAME records for this thread's stack trace
1746 int depth = stack_trace->get_stack_depth();
1747 int thread_frame_start = frame_serial_num;
1748 for (int j=0; j < depth; j++) {
1749 StackFrameInfo* frame = stack_trace->stack_frame_at(j);
1750 methodOop m = frame->method();
1751 int class_serial_num = _klass_map->find(Klass::cast(m->method_holder()));
1752 // the class serial number starts from 1
1753 assert(class_serial_num > 0, "class not found");
1754 DumperSupport::dump_stack_frame(writer(), ++frame_serial_num, class_serial_num, m, frame->bci());
1755 }
1756
1757 // write HPROF_TRACE record for one thread
1758 DumperSupport::write_header(writer(), HPROF_TRACE, 3*sizeof(u4) + depth*oopSize);
1759 int stack_serial_num = _num_threads + STACK_TRACE_ID;
1760 writer()->write_u4(stack_serial_num); // stack trace serial number
1761 writer()->write_u4((u4) _num_threads); // thread serial number
1762 writer()->write_u4(depth); // frame count
1763 for (int j=1; j <= depth; j++) {
1764 writer()->write_id(thread_frame_start + j);
1765 }
1766 }
1767 }
1768 }
1649 1769
1650 // dump the heap to given path. 1770 // dump the heap to given path.
1651 int HeapDumper::dump(const char* path) { 1771 int HeapDumper::dump(const char* path) {
1652 assert(path != NULL && strlen(path) > 0, "path missing"); 1772 assert(path != NULL && strlen(path) > 0, "path missing");
1653 1773

mercurial