< prev index next >

src/hotspot/share/memory/heap.cpp

Print this page

        

*** 1,7 **** /* ! * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. --- 1,7 ---- /* ! * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.
*** 53,73 **** _adapter_count = 0; _full_count = 0; } void CodeHeap::mark_segmap_as_free(size_t beg, size_t end) { assert( beg < _number_of_committed_segments, "interval begin out of bounds"); assert(beg < end && end <= _number_of_committed_segments, "interval end out of bounds"); // setup _segmap pointers for faster indexing address p = (address)_segmap.low() + beg; address q = (address)_segmap.low() + end; // initialize interval ! while (p < q) *p++ = free_sentinel; } ! void CodeHeap::mark_segmap_as_used(size_t beg, size_t end) { assert( beg < _number_of_committed_segments, "interval begin out of bounds"); assert(beg < end && end <= _number_of_committed_segments, "interval end out of bounds"); // setup _segmap pointers for faster indexing address p = (address)_segmap.low() + beg; --- 53,81 ---- _adapter_count = 0; _full_count = 0; } + // The segmap is marked free for that part of the heap + // which has not been allocated yet (beyond _next_segment). + // "Allocated" space in this context means there exists a + // HeapBlock or a FreeBlock describing this space. void CodeHeap::mark_segmap_as_free(size_t beg, size_t end) { assert( beg < _number_of_committed_segments, "interval begin out of bounds"); assert(beg < end && end <= _number_of_committed_segments, "interval end out of bounds"); // setup _segmap pointers for faster indexing address p = (address)_segmap.low() + beg; address q = (address)_segmap.low() + end; // initialize interval ! memset(p, free_sentinel, q-p); } ! // Don't get confused here. ! // All existing blocks, no matter if they are used() or free(), ! // have their segmap marked as used. This allows to find the ! // block header (HeapBlock or FreeBlock) for any pointer ! // within the allocated range (upper limit: _next_segment). void CodeHeap::mark_segmap_as_used(size_t beg, size_t end) { assert( beg < _number_of_committed_segments, "interval begin out of bounds"); assert(beg < end && end <= _number_of_committed_segments, "interval end out of bounds"); // setup _segmap pointers for faster indexing address p = (address)_segmap.low() + beg;
*** 187,197 **** NOT_PRODUCT(verify()); HeapBlock* block = search_freelist(number_of_segments); NOT_PRODUCT(verify()); if (block != NULL) { - assert(block->length() >= number_of_segments && block->length() < number_of_segments + CodeCacheMinBlockLength, "sanity check"); assert(!block->free(), "must be marked free"); guarantee((char*) block >= _memory.low_boundary() && (char*) block < _memory.high(), "The newly allocated block " INTPTR_FORMAT " is not within the heap " "starting with " INTPTR_FORMAT " and ending with " INTPTR_FORMAT, p2i(block), p2i(_memory.low_boundary()), p2i(_memory.high())); --- 195,204 ----
*** 220,242 **** } else { return NULL; } } void CodeHeap::deallocate_tail(void* p, size_t used_size) { assert(p == find_start(p), "illegal deallocation"); // Find start of HeapBlock HeapBlock* b = (((HeapBlock *)p) - 1); assert(b->allocated_space() == p, "sanity check"); ! size_t used_number_of_segments = size_to_segments(used_size + header_size()); size_t actual_number_of_segments = b->length(); guarantee(used_number_of_segments <= actual_number_of_segments, "Must be!"); ! guarantee(b == block_at(_next_segment - actual_number_of_segments), "Intermediate allocation!"); ! size_t number_of_segments_to_deallocate = actual_number_of_segments - used_number_of_segments; ! _next_segment -= number_of_segments_to_deallocate; ! mark_segmap_as_free(_next_segment, _next_segment + number_of_segments_to_deallocate); ! b->initialize(used_number_of_segments); } void CodeHeap::deallocate(void* p) { assert(p == find_start(p), "illegal deallocation"); // Find start of HeapBlock --- 227,277 ---- } else { return NULL; } } + // Split the given block into two at the given segment. + // This is helpful when a block was allocated too large + // to trim off the unused space at the end (interpreter). + // It also helps with splitting a large free block during allocation. + // Usage state (used or free) must be set by caller since + // we don't know if the resulting blocks will be used or free. + // split_at is the segment number (relative to segment_for(b)) + // where the split happens. The segment with relative + // number split_at is the first segment of the split-off block. + HeapBlock* CodeHeap::split_block(HeapBlock *b, size_t split_at) { + if (b == NULL) return NULL; + // After the split, both blocks must have a size of at least CodeCacheMinBlockLength + assert((split_at >= CodeCacheMinBlockLength) && (split_at + CodeCacheMinBlockLength <= b->length()), + "split position(%d) out of range [0..%d]", (int)split_at, (int)b->length()); + size_t split_segment = segment_for(b) + split_at; + size_t b_size = b->length(); + size_t newb_size = b_size - split_at; + + HeapBlock* newb = block_at(split_segment); + newb->set_length(newb_size); + mark_segmap_as_used(segment_for(newb), segment_for(newb) + newb_size); + b->set_length(split_at); + return newb; + } + void CodeHeap::deallocate_tail(void* p, size_t used_size) { assert(p == find_start(p), "illegal deallocation"); // Find start of HeapBlock HeapBlock* b = (((HeapBlock *)p) - 1); assert(b->allocated_space() == p, "sanity check"); ! size_t actual_number_of_segments = b->length(); + size_t used_number_of_segments = size_to_segments(used_size + header_size()); + size_t unused_number_of_segments = actual_number_of_segments - used_number_of_segments; guarantee(used_number_of_segments <= actual_number_of_segments, "Must be!"); ! ! HeapBlock* f = split_block(b, used_number_of_segments); ! DEBUG_ONLY(memset((void *)f->allocated_space(), badCodeHeapFreeVal, ! segments_to_size(unused_number_of_segments) - sizeof(HeapBlock))); ! add_to_freelist(f); ! NOT_PRODUCT(verify()); } void CodeHeap::deallocate(void* p) { assert(p == find_start(p), "illegal deallocation"); // Find start of HeapBlock
*** 428,439 **** _freelist_segments += b->length(); b->set_free(); // First element in list? if (_freelist == NULL) { - _freelist = b; b->set_link(NULL); return; } // Since the freelist is ordered (smaller addresses -> larger addresses) and the // element we want to insert into the freelist has a smaller address than the first --- 463,474 ---- _freelist_segments += b->length(); b->set_free(); // First element in list? if (_freelist == NULL) { b->set_link(NULL); + _freelist = b; return; } // Since the freelist is ordered (smaller addresses -> larger addresses) and the // element we want to insert into the freelist has a smaller address than the first
*** 461,487 **** /** * Search freelist for an entry on the list with the best fit. * @return NULL, if no one was found */ ! FreeBlock* CodeHeap::search_freelist(size_t length) { FreeBlock* found_block = NULL; FreeBlock* found_prev = NULL; ! size_t found_length = 0; FreeBlock* prev = NULL; FreeBlock* cur = _freelist; ! // Search for first block that fits while(cur != NULL) { ! if (cur->length() >= length) { ! // Remember block, its previous element, and its length found_block = cur; found_prev = prev; ! found_length = found_block->length(); ! break; } // Next element in list prev = cur; cur = cur->link(); } --- 496,530 ---- /** * Search freelist for an entry on the list with the best fit. * @return NULL, if no one was found */ ! HeapBlock* CodeHeap::search_freelist(size_t length) { FreeBlock* found_block = NULL; FreeBlock* found_prev = NULL; ! size_t found_length = _next_segment; // max it out to begin with + HeapBlock* res = NULL; FreeBlock* prev = NULL; FreeBlock* cur = _freelist; ! length = length < CodeCacheMinBlockLength ? CodeCacheMinBlockLength : length; ! ! // Search for best-fitting block while(cur != NULL) { ! size_t cur_length = cur->length(); ! if (cur_length == length) { ! // We have a perfect fit found_block = cur; found_prev = prev; ! found_length = cur_length; break; + } else if ((cur_length > length) && (cur_length < found_length)) { + // This is a new, closer fit. Remember block, its previous element, and its length + found_block = cur; + found_prev = prev; + found_length = cur_length; } // Next element in list prev = cur; cur = cur->link(); }
*** 502,525 **** } else { assert((found_prev->link() == found_block), "sanity check"); // Unmap element found_prev->set_link(found_block->link()); } } else { ! // Truncate block and return a pointer to the following block ! // Set used bit and length on new block ! found_block->set_length(found_length - length); ! found_block = following_block(found_block); ! ! size_t beg = segment_for(found_block); ! mark_segmap_as_used(beg, beg + length); ! found_block->set_length(length); } ! found_block->set_used(); _freelist_segments -= length; ! return found_block; } //---------------------------------------------------------------------------- // Non-product code --- 545,566 ---- } else { assert((found_prev->link() == found_block), "sanity check"); // Unmap element found_prev->set_link(found_block->link()); } + res = found_block; } else { ! // Truncate the free block and return the truncated part ! // as new HeapBlock. The remaining free block does not ! // need to be updated, except for it's length. Truncating ! // the segment map does not invalidate the leading part. ! res = split_block(found_block, found_length - length); } ! res->set_used(); _freelist_segments -= length; ! return res; } //---------------------------------------------------------------------------- // Non-product code
*** 547,556 **** --- 588,616 ---- } // Verify that the freelist contains the same number of blocks // than free blocks found on the full list. assert(count == 0, "missing free blocks"); + // Verify segment map marking. + // All allocated segments, no matter if in a free or used block, + // must be marked "in use". + address seg_map = (address)_segmap.low(); + size_t nseg = 0; + for(HeapBlock* b = first_block(); b != NULL; b = next_block(b)) { + size_t seg1 = segment_for(b); + size_t segn = seg1 + b->length(); + for (size_t i = seg1; i < segn; i++) { + nseg++; + if (is_segment_unused(seg_map[i])) { + warning("CodeHeap: unused segment. %d [%d..%d], %s block", (int)i, (int)seg1, (int)segn, b->free()? "free":"used"); + } + } + } + if (nseg != _next_segment) { + warning("CodeHeap: segment count mismatch. found %d, expected %d.", (int)nseg, (int)_next_segment); + } + // Verify that the number of free blocks is not out of hand. static int free_block_threshold = 10000; if (count > free_block_threshold) { warning("CodeHeap: # of free blocks > %d", free_block_threshold); // Double the warning limit
< prev index next >