< 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 >