1 /* 2 * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 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 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #include "precompiled.hpp" 26 #include "memory/allocation.hpp" 27 #include "memory/allocation.inline.hpp" 28 #include "memory/resourceArea.hpp" 29 #include "runtime/os.hpp" 30 #include "runtime/task.hpp" 31 #include "runtime/threadCritical.hpp" 32 #include "utilities/ostream.hpp" 33 #ifdef TARGET_OS_FAMILY_linux 34 # include "os_linux.inline.hpp" 35 #endif 36 #ifdef TARGET_OS_FAMILY_solaris 37 # include "os_solaris.inline.hpp" 38 #endif 39 #ifdef TARGET_OS_FAMILY_windows 40 # include "os_windows.inline.hpp" 41 #endif 42 43 void* CHeapObj::operator new(size_t size){ 44 return (void *) AllocateHeap(size, "CHeapObj-new"); 45 } 46 47 void* CHeapObj::operator new (size_t size, const std::nothrow_t& nothrow_constant) { 48 char* p = (char*) os::malloc(size); 49 #ifdef ASSERT 50 if (PrintMallocFree) trace_heap_malloc(size, "CHeapObj-new", p); 51 #endif 52 return p; 53 } 54 55 void CHeapObj::operator delete(void* p){ 56 FreeHeap(p); 57 } 58 59 void* StackObj::operator new(size_t size) { ShouldNotCallThis(); return 0; }; 60 void StackObj::operator delete(void* p) { ShouldNotCallThis(); }; 61 void* _ValueObj::operator new(size_t size) { ShouldNotCallThis(); return 0; }; 62 void _ValueObj::operator delete(void* p) { ShouldNotCallThis(); }; 63 64 void* ResourceObj::operator new(size_t size, allocation_type type) { 65 address res; 66 switch (type) { 67 case C_HEAP: 68 res = (address)AllocateHeap(size, "C_Heap: ResourceOBJ"); 69 DEBUG_ONLY(set_allocation_type(res, C_HEAP);) 70 break; 71 case RESOURCE_AREA: 72 // new(size) sets allocation type RESOURCE_AREA. 73 res = (address)operator new(size); 74 break; 75 default: 76 ShouldNotReachHere(); 77 } 78 return res; 79 } 80 81 void ResourceObj::operator delete(void* p) { 82 assert(((ResourceObj *)p)->allocated_on_C_heap(), 83 "delete only allowed for C_HEAP objects"); 84 DEBUG_ONLY(((ResourceObj *)p)->_allocation_t[0] = (uintptr_t)badHeapOopVal;) 85 FreeHeap(p); 86 } 87 88 #ifdef ASSERT 89 void ResourceObj::set_allocation_type(address res, allocation_type type) { 90 // Set allocation type in the resource object 91 uintptr_t allocation = (uintptr_t)res; 92 assert((allocation & allocation_mask) == 0, "address should be aligned to 4 bytes at least"); 93 assert(type <= allocation_mask, "incorrect allocation type"); 94 ResourceObj* resobj = (ResourceObj *)res; 95 resobj->_allocation_t[0] = ~(allocation + type); 96 if (type != STACK_OR_EMBEDDED) { 97 // Called from operator new() and CollectionSetChooser(), 98 // set verification value. 99 resobj->_allocation_t[1] = (uintptr_t)&(resobj->_allocation_t[1]) + type; 100 } 101 } 102 103 ResourceObj::allocation_type ResourceObj::get_allocation_type() const { 104 assert(~(_allocation_t[0] | allocation_mask) == (uintptr_t)this, "lost resource object"); 105 return (allocation_type)((~_allocation_t[0]) & allocation_mask); 106 } 107 108 bool ResourceObj::is_type_set() const { 109 allocation_type type = (allocation_type)(_allocation_t[1] & allocation_mask); 110 return get_allocation_type() == type && 111 (_allocation_t[1] - type) == (uintptr_t)(&_allocation_t[1]); 112 } 113 114 ResourceObj::ResourceObj() { // default constructor 115 if (~(_allocation_t[0] | allocation_mask) != (uintptr_t)this) { 116 // Operator new() is not called for allocations 117 // on stack and for embedded objects. 118 set_allocation_type((address)this, STACK_OR_EMBEDDED); 119 } else if (allocated_on_stack()) { // STACK_OR_EMBEDDED 120 // For some reason we got a value which resembles 121 // an embedded or stack object (operator new() does not 122 // set such type). Keep it since it is valid value 123 // (even if it was garbage). 124 // Ignore garbage in other fields. 125 } else if (is_type_set()) { 126 // Operator new() was called and type was set. 127 assert(!allocated_on_stack(), 128 err_msg("not embedded or stack, this(" PTR_FORMAT ") type %d a[0]=(" PTR_FORMAT ") a[1]=(" PTR_FORMAT ")", 129 this, get_allocation_type(), _allocation_t[0], _allocation_t[1])); 130 } else { 131 // Operator new() was not called. 132 // Assume that it is embedded or stack object. 133 set_allocation_type((address)this, STACK_OR_EMBEDDED); 134 } 135 _allocation_t[1] = 0; // Zap verification value 136 } 137 138 ResourceObj::ResourceObj(const ResourceObj& r) { // default copy constructor 139 // Used in ClassFileParser::parse_constant_pool_entries() for ClassFileStream. 140 // Note: garbage may resembles valid value. 141 assert(~(_allocation_t[0] | allocation_mask) != (uintptr_t)this || !is_type_set(), 142 err_msg("embedded or stack only, this(" PTR_FORMAT ") type %d a[0]=(" PTR_FORMAT ") a[1]=(" PTR_FORMAT ")", 143 this, get_allocation_type(), _allocation_t[0], _allocation_t[1])); 144 set_allocation_type((address)this, STACK_OR_EMBEDDED); 145 _allocation_t[1] = 0; // Zap verification value 146 } 147 148 ResourceObj& ResourceObj::operator=(const ResourceObj& r) { // default copy assignment 149 // Used in InlineTree::ok_to_inline() for WarmCallInfo. 150 assert(allocated_on_stack(), 151 err_msg("copy only into local, this(" PTR_FORMAT ") type %d a[0]=(" PTR_FORMAT ") a[1]=(" PTR_FORMAT ")", 152 this, get_allocation_type(), _allocation_t[0], _allocation_t[1])); 153 // Keep current _allocation_t value; 154 return *this; 155 } 156 157 ResourceObj::~ResourceObj() { 158 // allocated_on_C_heap() also checks that encoded (in _allocation) address == this. 159 if (!allocated_on_C_heap()) { // ResourceObj::delete() will zap _allocation for C_heap. 160 _allocation_t[0] = (uintptr_t)badHeapOopVal; // zap type 161 } 162 } 163 #endif // ASSERT 164 165 166 void trace_heap_malloc(size_t size, const char* name, void* p) { 167 // A lock is not needed here - tty uses a lock internally 168 tty->print_cr("Heap malloc " INTPTR_FORMAT " " SIZE_FORMAT " %s", p, size, name == NULL ? "" : name); 169 } 170 171 172 void trace_heap_free(void* p) { 173 // A lock is not needed here - tty uses a lock internally 174 tty->print_cr("Heap free " INTPTR_FORMAT, p); 175 } 176 177 bool warn_new_operator = false; // see vm_main 178 179 //-------------------------------------------------------------------------------------- 180 // ChunkPool implementation 181 182 // MT-safe pool of chunks to reduce malloc/free thrashing 183 // NB: not using Mutex because pools are used before Threads are initialized 184 class ChunkPool { 185 Chunk* _first; // first cached Chunk; its first word points to next chunk 186 size_t _num_chunks; // number of unused chunks in pool 187 size_t _num_used; // number of chunks currently checked out 188 const size_t _size; // size of each chunk (must be uniform) 189 190 // Our three static pools 191 static ChunkPool* _large_pool; 192 static ChunkPool* _medium_pool; 193 static ChunkPool* _small_pool; 194 195 // return first element or null 196 void* get_first() { 197 Chunk* c = _first; 198 if (_first) { 199 _first = _first->next(); 200 _num_chunks--; 201 } 202 return c; 203 } 204 205 public: 206 // All chunks in a ChunkPool has the same size 207 ChunkPool(size_t size) : _size(size) { _first = NULL; _num_chunks = _num_used = 0; } 208 209 // Allocate a new chunk from the pool (might expand the pool) 210 void* allocate(size_t bytes) { 211 assert(bytes == _size, "bad size"); 212 void* p = NULL; 213 { ThreadCritical tc; 214 _num_used++; 215 p = get_first(); 216 if (p == NULL) p = os::malloc(bytes); 217 } 218 if (p == NULL) 219 vm_exit_out_of_memory(bytes, "ChunkPool::allocate"); 220 221 return p; 222 } 223 224 // Return a chunk to the pool 225 void free(Chunk* chunk) { 226 assert(chunk->length() + Chunk::aligned_overhead_size() == _size, "bad size"); 227 ThreadCritical tc; 228 _num_used--; 229 230 // Add chunk to list 231 chunk->set_next(_first); 232 _first = chunk; 233 _num_chunks++; 234 } 235 236 // Prune the pool 237 void free_all_but(size_t n) { 238 // if we have more than n chunks, free all of them 239 ThreadCritical tc; 240 if (_num_chunks > n) { 241 // free chunks at end of queue, for better locality 242 Chunk* cur = _first; 243 for (size_t i = 0; i < (n - 1) && cur != NULL; i++) cur = cur->next(); 244 245 if (cur != NULL) { 246 Chunk* next = cur->next(); 247 cur->set_next(NULL); 248 cur = next; 249 250 // Free all remaining chunks 251 while(cur != NULL) { 252 next = cur->next(); 253 os::free(cur); 254 _num_chunks--; 255 cur = next; 256 } 257 } 258 } 259 } 260 261 // Accessors to preallocated pool's 262 static ChunkPool* large_pool() { assert(_large_pool != NULL, "must be initialized"); return _large_pool; } 263 static ChunkPool* medium_pool() { assert(_medium_pool != NULL, "must be initialized"); return _medium_pool; } 264 static ChunkPool* small_pool() { assert(_small_pool != NULL, "must be initialized"); return _small_pool; } 265 266 static void initialize() { 267 _large_pool = new ChunkPool(Chunk::size + Chunk::aligned_overhead_size()); 268 _medium_pool = new ChunkPool(Chunk::medium_size + Chunk::aligned_overhead_size()); 269 _small_pool = new ChunkPool(Chunk::init_size + Chunk::aligned_overhead_size()); 270 } 271 272 static void clean() { 273 enum { BlocksToKeep = 5 }; 274 _small_pool->free_all_but(BlocksToKeep); 275 _medium_pool->free_all_but(BlocksToKeep); 276 _large_pool->free_all_but(BlocksToKeep); 277 } 278 }; 279 280 ChunkPool* ChunkPool::_large_pool = NULL; 281 ChunkPool* ChunkPool::_medium_pool = NULL; 282 ChunkPool* ChunkPool::_small_pool = NULL; 283 284 void chunkpool_init() { 285 ChunkPool::initialize(); 286 } 287 288 void 289 Chunk::clean_chunk_pool() { 290 ChunkPool::clean(); 291 } 292 293 294 //-------------------------------------------------------------------------------------- 295 // ChunkPoolCleaner implementation 296 // 297 298 class ChunkPoolCleaner : public PeriodicTask { 299 enum { CleaningInterval = 5000 }; // cleaning interval in ms 300 301 public: 302 ChunkPoolCleaner() : PeriodicTask(CleaningInterval) {} 303 void task() { 304 ChunkPool::clean(); 305 } 306 }; 307 308 //-------------------------------------------------------------------------------------- 309 // Chunk implementation 310 311 void* Chunk::operator new(size_t requested_size, size_t length) { 312 // requested_size is equal to sizeof(Chunk) but in order for the arena 313 // allocations to come out aligned as expected the size must be aligned 314 // to expected arean alignment. 315 // expect requested_size but if sizeof(Chunk) doesn't match isn't proper size we must align it. 316 assert(ARENA_ALIGN(requested_size) == aligned_overhead_size(), "Bad alignment"); 317 size_t bytes = ARENA_ALIGN(requested_size) + length; 318 switch (length) { 319 case Chunk::size: return ChunkPool::large_pool()->allocate(bytes); 320 case Chunk::medium_size: return ChunkPool::medium_pool()->allocate(bytes); 321 case Chunk::init_size: return ChunkPool::small_pool()->allocate(bytes); 322 default: { 323 void *p = os::malloc(bytes); 324 if (p == NULL) 325 vm_exit_out_of_memory(bytes, "Chunk::new"); 326 return p; 327 } 328 } 329 } 330 331 void Chunk::operator delete(void* p) { 332 Chunk* c = (Chunk*)p; 333 switch (c->length()) { 334 case Chunk::size: ChunkPool::large_pool()->free(c); break; 335 case Chunk::medium_size: ChunkPool::medium_pool()->free(c); break; 336 case Chunk::init_size: ChunkPool::small_pool()->free(c); break; 337 default: os::free(c); 338 } 339 } 340 341 Chunk::Chunk(size_t length) : _len(length) { 342 _next = NULL; // Chain on the linked list 343 } 344 345 346 void Chunk::chop() { 347 Chunk *k = this; 348 while( k ) { 349 Chunk *tmp = k->next(); 350 // clear out this chunk (to detect allocation bugs) 351 if (ZapResourceArea) memset(k->bottom(), badResourceValue, k->length()); 352 delete k; // Free chunk (was malloc'd) 353 k = tmp; 354 } 355 } 356 357 void Chunk::next_chop() { 358 _next->chop(); 359 _next = NULL; 360 } 361 362 363 void Chunk::start_chunk_pool_cleaner_task() { 364 #ifdef ASSERT 365 static bool task_created = false; 366 assert(!task_created, "should not start chuck pool cleaner twice"); 367 task_created = true; 368 #endif 369 ChunkPoolCleaner* cleaner = new ChunkPoolCleaner(); 370 cleaner->enroll(); 371 } 372 373 //------------------------------Arena------------------------------------------ 374 375 Arena::Arena(size_t init_size) { 376 size_t round_size = (sizeof (char *)) - 1; 377 init_size = (init_size+round_size) & ~round_size; 378 _first = _chunk = new (init_size) Chunk(init_size); 379 _hwm = _chunk->bottom(); // Save the cached hwm, max 380 _max = _chunk->top(); 381 set_size_in_bytes(init_size); 382 } 383 384 Arena::Arena() { 385 _first = _chunk = new (Chunk::init_size) Chunk(Chunk::init_size); 386 _hwm = _chunk->bottom(); // Save the cached hwm, max 387 _max = _chunk->top(); 388 set_size_in_bytes(Chunk::init_size); 389 } 390 391 Arena::Arena(Arena *a) : _chunk(a->_chunk), _hwm(a->_hwm), _max(a->_max), _first(a->_first) { 392 set_size_in_bytes(a->size_in_bytes()); 393 } 394 395 Arena *Arena::move_contents(Arena *copy) { 396 copy->destruct_contents(); 397 copy->_chunk = _chunk; 398 copy->_hwm = _hwm; 399 copy->_max = _max; 400 copy->_first = _first; 401 copy->set_size_in_bytes(size_in_bytes()); 402 // Destroy original arena 403 reset(); 404 return copy; // Return Arena with contents 405 } 406 407 Arena::~Arena() { 408 destruct_contents(); 409 } 410 411 // Destroy this arenas contents and reset to empty 412 void Arena::destruct_contents() { 413 if (UseMallocOnly && _first != NULL) { 414 char* end = _first->next() ? _first->top() : _hwm; 415 free_malloced_objects(_first, _first->bottom(), end, _hwm); 416 } 417 _first->chop(); 418 reset(); 419 } 420 421 422 // Total of all Chunks in arena 423 size_t Arena::used() const { 424 size_t sum = _chunk->length() - (_max-_hwm); // Size leftover in this Chunk 425 register Chunk *k = _first; 426 while( k != _chunk) { // Whilst have Chunks in a row 427 sum += k->length(); // Total size of this Chunk 428 k = k->next(); // Bump along to next Chunk 429 } 430 return sum; // Return total consumed space. 431 } 432 433 void Arena::signal_out_of_memory(size_t sz, const char* whence) const { 434 vm_exit_out_of_memory(sz, whence); 435 } 436 437 // Grow a new Chunk 438 void* Arena::grow( size_t x ) { 439 // Get minimal required size. Either real big, or even bigger for giant objs 440 size_t len = MAX2(x, (size_t) Chunk::size); 441 442 Chunk *k = _chunk; // Get filled-up chunk address 443 _chunk = new (len) Chunk(len); 444 445 if (_chunk == NULL) { 446 signal_out_of_memory(len * Chunk::aligned_overhead_size(), "Arena::grow"); 447 } 448 449 if (k) k->set_next(_chunk); // Append new chunk to end of linked list 450 else _first = _chunk; 451 _hwm = _chunk->bottom(); // Save the cached hwm, max 452 _max = _chunk->top(); 453 set_size_in_bytes(size_in_bytes() + len); 454 void* result = _hwm; 455 _hwm += x; 456 return result; 457 } 458 459 460 461 // Reallocate storage in Arena. 462 void *Arena::Arealloc(void* old_ptr, size_t old_size, size_t new_size) { 463 assert(new_size >= 0, "bad size"); 464 if (new_size == 0) return NULL; 465 #ifdef ASSERT 466 if (UseMallocOnly) { 467 // always allocate a new object (otherwise we'll free this one twice) 468 char* copy = (char*)Amalloc(new_size); 469 size_t n = MIN2(old_size, new_size); 470 if (n > 0) memcpy(copy, old_ptr, n); 471 Afree(old_ptr,old_size); // Mostly done to keep stats accurate 472 return copy; 473 } 474 #endif 475 char *c_old = (char*)old_ptr; // Handy name 476 // Stupid fast special case 477 if( new_size <= old_size ) { // Shrink in-place 478 if( c_old+old_size == _hwm) // Attempt to free the excess bytes 479 _hwm = c_old+new_size; // Adjust hwm 480 return c_old; 481 } 482 483 // make sure that new_size is legal 484 size_t corrected_new_size = ARENA_ALIGN(new_size); 485 486 // See if we can resize in-place 487 if( (c_old+old_size == _hwm) && // Adjusting recent thing 488 (c_old+corrected_new_size <= _max) ) { // Still fits where it sits 489 _hwm = c_old+corrected_new_size; // Adjust hwm 490 return c_old; // Return old pointer 491 } 492 493 // Oops, got to relocate guts 494 void *new_ptr = Amalloc(new_size); 495 memcpy( new_ptr, c_old, old_size ); 496 Afree(c_old,old_size); // Mostly done to keep stats accurate 497 return new_ptr; 498 } 499 500 501 // Determine if pointer belongs to this Arena or not. 502 bool Arena::contains( const void *ptr ) const { 503 #ifdef ASSERT 504 if (UseMallocOnly) { 505 // really slow, but not easy to make fast 506 if (_chunk == NULL) return false; 507 char** bottom = (char**)_chunk->bottom(); 508 for (char** p = (char**)_hwm - 1; p >= bottom; p--) { 509 if (*p == ptr) return true; 510 } 511 for (Chunk *c = _first; c != NULL; c = c->next()) { 512 if (c == _chunk) continue; // current chunk has been processed 513 char** bottom = (char**)c->bottom(); 514 for (char** p = (char**)c->top() - 1; p >= bottom; p--) { 515 if (*p == ptr) return true; 516 } 517 } 518 return false; 519 } 520 #endif 521 if( (void*)_chunk->bottom() <= ptr && ptr < (void*)_hwm ) 522 return true; // Check for in this chunk 523 for (Chunk *c = _first; c; c = c->next()) { 524 if (c == _chunk) continue; // current chunk has been processed 525 if ((void*)c->bottom() <= ptr && ptr < (void*)c->top()) { 526 return true; // Check for every chunk in Arena 527 } 528 } 529 return false; // Not in any Chunk, so not in Arena 530 } 531 532 533 #ifdef ASSERT 534 void* Arena::malloc(size_t size) { 535 assert(UseMallocOnly, "shouldn't call"); 536 // use malloc, but save pointer in res. area for later freeing 537 char** save = (char**)internal_malloc_4(sizeof(char*)); 538 return (*save = (char*)os::malloc(size)); 539 } 540 541 // for debugging with UseMallocOnly 542 void* Arena::internal_malloc_4(size_t x) { 543 assert( (x&(sizeof(char*)-1)) == 0, "misaligned size" ); 544 check_for_overflow(x, "Arena::internal_malloc_4"); 545 if (_hwm + x > _max) { 546 return grow(x); 547 } else { 548 char *old = _hwm; 549 _hwm += x; 550 return old; 551 } 552 } 553 #endif 554 555 556 //-------------------------------------------------------------------------------------- 557 // Non-product code 558 559 #ifndef PRODUCT 560 // The global operator new should never be called since it will usually indicate 561 // a memory leak. Use CHeapObj as the base class of such objects to make it explicit 562 // that they're allocated on the C heap. 563 // Commented out in product version to avoid conflicts with third-party C++ native code. 564 // %% note this is causing a problem on solaris debug build. the global 565 // new is being called from jdk source and causing data corruption. 566 // src/share/native/sun/awt/font/fontmanager/textcache/hsMemory.cpp::hsSoftNew 567 // define CATCH_OPERATOR_NEW_USAGE if you want to use this. 568 #ifdef CATCH_OPERATOR_NEW_USAGE 569 void* operator new(size_t size){ 570 static bool warned = false; 571 if (!warned && warn_new_operator) 572 warning("should not call global (default) operator new"); 573 warned = true; 574 return (void *) AllocateHeap(size, "global operator new"); 575 } 576 #endif 577 578 void AllocatedObj::print() const { print_on(tty); } 579 void AllocatedObj::print_value() const { print_value_on(tty); } 580 581 void AllocatedObj::print_on(outputStream* st) const { 582 st->print_cr("AllocatedObj(" INTPTR_FORMAT ")", this); 583 } 584 585 void AllocatedObj::print_value_on(outputStream* st) const { 586 st->print("AllocatedObj(" INTPTR_FORMAT ")", this); 587 } 588 589 julong Arena::_bytes_allocated = 0; 590 591 void Arena::inc_bytes_allocated(size_t x) { inc_stat_counter(&_bytes_allocated, x); } 592 593 AllocStats::AllocStats() { 594 start_mallocs = os::num_mallocs; 595 start_frees = os::num_frees; 596 start_malloc_bytes = os::alloc_bytes; 597 start_mfree_bytes = os::free_bytes; 598 start_res_bytes = Arena::_bytes_allocated; 599 } 600 601 julong AllocStats::num_mallocs() { return os::num_mallocs - start_mallocs; } 602 julong AllocStats::alloc_bytes() { return os::alloc_bytes - start_malloc_bytes; } 603 julong AllocStats::num_frees() { return os::num_frees - start_frees; } 604 julong AllocStats::free_bytes() { return os::free_bytes - start_mfree_bytes; } 605 julong AllocStats::resource_bytes() { return Arena::_bytes_allocated - start_res_bytes; } 606 void AllocStats::print() { 607 tty->print_cr(UINT64_FORMAT " mallocs (" UINT64_FORMAT "MB), " 608 UINT64_FORMAT" frees (" UINT64_FORMAT "MB), " UINT64_FORMAT "MB resrc", 609 num_mallocs(), alloc_bytes()/M, num_frees(), free_bytes()/M, resource_bytes()/M); 610 } 611 612 613 // debugging code 614 inline void Arena::free_all(char** start, char** end) { 615 for (char** p = start; p < end; p++) if (*p) os::free(*p); 616 } 617 618 void Arena::free_malloced_objects(Chunk* chunk, char* hwm, char* max, char* hwm2) { 619 assert(UseMallocOnly, "should not call"); 620 // free all objects malloced since resource mark was created; resource area 621 // contains their addresses 622 if (chunk->next()) { 623 // this chunk is full, and some others too 624 for (Chunk* c = chunk->next(); c != NULL; c = c->next()) { 625 char* top = c->top(); 626 if (c->next() == NULL) { 627 top = hwm2; // last junk is only used up to hwm2 628 assert(c->contains(hwm2), "bad hwm2"); 629 } 630 free_all((char**)c->bottom(), (char**)top); 631 } 632 assert(chunk->contains(hwm), "bad hwm"); 633 assert(chunk->contains(max), "bad max"); 634 free_all((char**)hwm, (char**)max); 635 } else { 636 // this chunk was partially used 637 assert(chunk->contains(hwm), "bad hwm"); 638 assert(chunk->contains(hwm2), "bad hwm2"); 639 free_all((char**)hwm, (char**)hwm2); 640 } 641 } 642 643 644 ReallocMark::ReallocMark() { 645 #ifdef ASSERT 646 Thread *thread = ThreadLocalStorage::get_thread_slow(); 647 _nesting = thread->resource_area()->nesting(); 648 #endif 649 } 650 651 void ReallocMark::check() { 652 #ifdef ASSERT 653 if (_nesting != Thread::current()->resource_area()->nesting()) { 654 fatal("allocation bug: array could grow within nested ResourceMark"); 655 } 656 #endif 657 } 658 659 #endif // Non-product