Mercurial > hg > graal-jvmci-8
comparison src/share/vm/services/memSnapshot.cpp @ 6979:fb3190e77d3c
8001592: NMT: assertion failed: assert(_amount >= amt) failed: Just check: memBaseline.hpp:180
Summary: Fixed NMT that miscounted arena memory when it is used as value or stack object.
Reviewed-by: acorn, coleenp
author | zgu |
---|---|
date | Fri, 09 Nov 2012 19:24:31 -0500 |
parents | 69ad7823b1ca |
children | 8c413497f434 |
comparison
equal
deleted
inserted
replaced
6938:8940ddc1036f | 6979:fb3190e77d3c |
---|---|
48 tty->print_cr(" (release)"); | 48 tty->print_cr(" (release)"); |
49 } else { | 49 } else { |
50 tty->print_cr(" (tag)"); | 50 tty->print_cr(" (tag)"); |
51 } | 51 } |
52 } else { | 52 } else { |
53 if (rec->is_arena_size_record()) { | 53 if (rec->is_arena_memory_record()) { |
54 tty->print_cr(" (arena size)"); | 54 tty->print_cr(" (arena size)"); |
55 } else if (rec->is_allocation_record()) { | 55 } else if (rec->is_allocation_record()) { |
56 tty->print_cr(" (malloc)"); | 56 tty->print_cr(" (malloc)"); |
57 } else { | 57 } else { |
58 tty->print_cr(" (free)"); | 58 tty->print_cr(" (free)"); |
388 delete _lock; | 388 delete _lock; |
389 _lock = NULL; | 389 _lock = NULL; |
390 } | 390 } |
391 } | 391 } |
392 | 392 |
393 void MemSnapshot::copy_pointer(MemPointerRecord* dest, const MemPointerRecord* src) { | 393 |
394 void MemSnapshot::copy_seq_pointer(MemPointerRecord* dest, const MemPointerRecord* src) { | |
394 assert(dest != NULL && src != NULL, "Just check"); | 395 assert(dest != NULL && src != NULL, "Just check"); |
395 assert(dest->addr() == src->addr(), "Just check"); | 396 assert(dest->addr() == src->addr(), "Just check"); |
396 | 397 assert(dest->seq() > 0 && src->seq() > 0, "not sequenced"); |
397 MEMFLAGS flags = dest->flags(); | 398 |
399 if (MemTracker::track_callsite()) { | |
400 *(SeqMemPointerRecordEx*)dest = *(SeqMemPointerRecordEx*)src; | |
401 } else { | |
402 *(SeqMemPointerRecord*)dest = *(SeqMemPointerRecord*)src; | |
403 } | |
404 } | |
405 | |
406 void MemSnapshot::assign_pointer(MemPointerRecord*dest, const MemPointerRecord* src) { | |
407 assert(src != NULL && dest != NULL, "Just check"); | |
408 assert(dest->seq() == 0 && src->seq() >0, "cast away sequence"); | |
398 | 409 |
399 if (MemTracker::track_callsite()) { | 410 if (MemTracker::track_callsite()) { |
400 *(MemPointerRecordEx*)dest = *(MemPointerRecordEx*)src; | 411 *(MemPointerRecordEx*)dest = *(MemPointerRecordEx*)src; |
401 } else { | 412 } else { |
402 *dest = *src; | 413 *(MemPointerRecord*)dest = *(MemPointerRecord*)src; |
403 } | 414 } |
404 } | 415 } |
405 | 416 |
406 | 417 // merge a recorder to the staging area |
407 // merge a per-thread memory recorder to the staging area | |
408 bool MemSnapshot::merge(MemRecorder* rec) { | 418 bool MemSnapshot::merge(MemRecorder* rec) { |
409 assert(rec != NULL && !rec->out_of_memory(), "Just check"); | 419 assert(rec != NULL && !rec->out_of_memory(), "Just check"); |
410 | 420 |
411 SequencedRecordIterator itr(rec->pointer_itr()); | 421 SequencedRecordIterator itr(rec->pointer_itr()); |
412 | 422 |
413 MutexLockerEx lock(_lock, true); | 423 MutexLockerEx lock(_lock, true); |
414 MemPointerIterator malloc_staging_itr(_staging_area.malloc_data()); | 424 MemPointerIterator malloc_staging_itr(_staging_area.malloc_data()); |
415 MemPointerRecord *p1, *p2; | 425 MemPointerRecord* incoming_rec = (MemPointerRecord*) itr.current(); |
416 p1 = (MemPointerRecord*) itr.current(); | 426 MemPointerRecord* matched_rec; |
417 while (p1 != NULL) { | 427 |
418 if (p1->is_vm_pointer()) { | 428 while (incoming_rec != NULL) { |
429 if (incoming_rec->is_vm_pointer()) { | |
419 // we don't do anything with virtual memory records during merge | 430 // we don't do anything with virtual memory records during merge |
420 if (!_staging_area.vm_data()->append(p1)) { | 431 if (!_staging_area.vm_data()->append(incoming_rec)) { |
421 return false; | 432 return false; |
422 } | 433 } |
423 } else { | 434 } else { |
424 // locate matched record and/or also position the iterator to proper | 435 // locate matched record and/or also position the iterator to proper |
425 // location for this incoming record. | 436 // location for this incoming record. |
426 p2 = (MemPointerRecord*)malloc_staging_itr.locate(p1->addr()); | 437 matched_rec = (MemPointerRecord*)malloc_staging_itr.locate(incoming_rec->addr()); |
427 // we have not seen this memory block, so just add to staging area | 438 // we have not seen this memory block in this generation, |
428 if (p2 == NULL) { | 439 // so just add to staging area |
429 if (!malloc_staging_itr.insert(p1)) { | 440 if (matched_rec == NULL) { |
441 if (!malloc_staging_itr.insert(incoming_rec)) { | |
430 return false; | 442 return false; |
431 } | 443 } |
432 } else if (p1->addr() == p2->addr()) { | 444 } else if (incoming_rec->addr() == matched_rec->addr()) { |
433 MemPointerRecord* staging_next = (MemPointerRecord*)malloc_staging_itr.peek_next(); | 445 // whoever has higher sequence number wins |
434 // a memory block can have many tagging records, find right one to replace or | 446 if (incoming_rec->seq() > matched_rec->seq()) { |
435 // right position to insert | 447 copy_seq_pointer(matched_rec, incoming_rec); |
436 while (staging_next != NULL && staging_next->addr() == p1->addr()) { | 448 } |
437 if ((staging_next->flags() & MemPointerRecord::tag_masks) <= | 449 } else if (incoming_rec->addr() < matched_rec->addr()) { |
438 (p1->flags() & MemPointerRecord::tag_masks)) { | 450 if (!malloc_staging_itr.insert(incoming_rec)) { |
439 p2 = (MemPointerRecord*)malloc_staging_itr.next(); | |
440 staging_next = (MemPointerRecord*)malloc_staging_itr.peek_next(); | |
441 } else { | |
442 break; | |
443 } | |
444 } | |
445 int df = (p1->flags() & MemPointerRecord::tag_masks) - | |
446 (p2->flags() & MemPointerRecord::tag_masks); | |
447 if (df == 0) { | |
448 assert(p1->seq() > 0, "not sequenced"); | |
449 assert(p2->seq() > 0, "not sequenced"); | |
450 if (p1->seq() > p2->seq()) { | |
451 copy_pointer(p2, p1); | |
452 } | |
453 } else if (df < 0) { | |
454 if (!malloc_staging_itr.insert(p1)) { | |
455 return false; | |
456 } | |
457 } else { | |
458 if (!malloc_staging_itr.insert_after(p1)) { | |
459 return false; | |
460 } | |
461 } | |
462 } else if (p1->addr() < p2->addr()) { | |
463 if (!malloc_staging_itr.insert(p1)) { | |
464 return false; | 451 return false; |
465 } | 452 } |
466 } else { | 453 } else { |
467 if (!malloc_staging_itr.insert_after(p1)) { | 454 ShouldNotReachHere(); |
468 return false; | 455 } |
469 } | 456 } |
470 } | 457 incoming_rec = (MemPointerRecord*)itr.next(); |
471 } | |
472 p1 = (MemPointerRecord*)itr.next(); | |
473 } | 458 } |
474 NOT_PRODUCT(void check_staging_data();) | 459 NOT_PRODUCT(void check_staging_data();) |
475 return true; | 460 return true; |
476 } | 461 } |
477 | |
478 | 462 |
479 | 463 |
480 // promote data to next generation | 464 // promote data to next generation |
481 bool MemSnapshot::promote() { | 465 bool MemSnapshot::promote() { |
482 assert(_alloc_ptrs != NULL && _vm_ptrs != NULL, "Just check"); | 466 assert(_alloc_ptrs != NULL && _vm_ptrs != NULL, "Just check"); |
505 while (new_rec != NULL) { | 489 while (new_rec != NULL) { |
506 matched_rec = (MemPointerRecord*)malloc_snapshot_itr.locate(new_rec->addr()); | 490 matched_rec = (MemPointerRecord*)malloc_snapshot_itr.locate(new_rec->addr()); |
507 // found matched memory block | 491 // found matched memory block |
508 if (matched_rec != NULL && new_rec->addr() == matched_rec->addr()) { | 492 if (matched_rec != NULL && new_rec->addr() == matched_rec->addr()) { |
509 // snapshot already contains 'live' records | 493 // snapshot already contains 'live' records |
510 assert(matched_rec->is_allocation_record() || matched_rec->is_arena_size_record(), | 494 assert(matched_rec->is_allocation_record() || matched_rec->is_arena_memory_record(), |
511 "Sanity check"); | 495 "Sanity check"); |
512 // update block states | 496 // update block states |
513 if (new_rec->is_allocation_record() || new_rec->is_arena_size_record()) { | 497 if (new_rec->is_allocation_record()) { |
514 copy_pointer(matched_rec, new_rec); | 498 assign_pointer(matched_rec, new_rec); |
499 } else if (new_rec->is_arena_memory_record()) { | |
500 if (new_rec->size() == 0) { | |
501 // remove size record once size drops to 0 | |
502 malloc_snapshot_itr.remove(); | |
503 } else { | |
504 assign_pointer(matched_rec, new_rec); | |
505 } | |
515 } else { | 506 } else { |
516 // a deallocation record | 507 // a deallocation record |
517 assert(new_rec->is_deallocation_record(), "Sanity check"); | 508 assert(new_rec->is_deallocation_record(), "Sanity check"); |
518 // an arena record can be followed by a size record, we need to remove both | 509 // an arena record can be followed by a size record, we need to remove both |
519 if (matched_rec->is_arena_record()) { | 510 if (matched_rec->is_arena_record()) { |
520 MemPointerRecord* next = (MemPointerRecord*)malloc_snapshot_itr.peek_next(); | 511 MemPointerRecord* next = (MemPointerRecord*)malloc_snapshot_itr.peek_next(); |
521 if (next->is_arena_size_record()) { | 512 if (next->is_arena_memory_record() && next->is_memory_record_of_arena(matched_rec)) { |
522 // it has to match the arena record | |
523 assert(next->is_size_record_of_arena(matched_rec), "Sanity check"); | |
524 malloc_snapshot_itr.remove(); | 513 malloc_snapshot_itr.remove(); |
525 } | 514 } |
526 } | 515 } |
527 // the memory is deallocated, remove related record(s) | 516 // the memory is deallocated, remove related record(s) |
528 malloc_snapshot_itr.remove(); | 517 malloc_snapshot_itr.remove(); |
529 } | 518 } |
530 } else { | 519 } else { |
531 // it is a new record, insert into snapshot | 520 // don't insert size 0 record |
532 if (new_rec->is_arena_size_record()) { | 521 if (new_rec->is_arena_memory_record() && new_rec->size() == 0) { |
533 MemPointerRecord* prev = (MemPointerRecord*)malloc_snapshot_itr.peek_prev(); | 522 new_rec = NULL; |
534 if (prev == NULL || !prev->is_arena_record() || !new_rec->is_size_record_of_arena(prev)) { | 523 } |
535 // no matched arena record, ignore the size record | 524 |
536 new_rec = NULL; | |
537 } | |
538 } | |
539 // only 'live' record can go into snapshot | |
540 if (new_rec != NULL) { | 525 if (new_rec != NULL) { |
541 if (new_rec->is_allocation_record() || new_rec->is_arena_size_record()) { | 526 if (new_rec->is_allocation_record() || new_rec->is_arena_memory_record()) { |
542 if (matched_rec != NULL && new_rec->addr() > matched_rec->addr()) { | 527 if (matched_rec != NULL && new_rec->addr() > matched_rec->addr()) { |
543 if (!malloc_snapshot_itr.insert_after(new_rec)) { | 528 if (!malloc_snapshot_itr.insert_after(new_rec)) { |
544 return false; | 529 return false; |
545 } | 530 } |
546 } else { | 531 } else { |