/** * 计算当前线程的本地分配缓冲区的新大小 */ inline size_t ThreadLocalAllocBuffer::compute_size(size_t obj_size) { const size_t aligned_obj_size = align_object_size(obj_size); // Compute the size for the new TLAB. // The "last" tlab may be smaller to reduce fragmentation. // unsafe_max_tlab_alloc is just a hint. const size_t available_size = Universe::heap()->unsafe_max_tlab_alloc(myThread()) / HeapWordSize; size_t new_tlab_size = MIN2(available_size, desired_size() + aligned_obj_size); // Make sure there's enough room for object and filler int[]. const size_t obj_plus_filler_size = aligned_obj_size + alignment_reserve(); if (new_tlab_size < obj_plus_filler_size) { // If there isn't enough room for the allocation, return failure. if (PrintTLAB && Verbose) { gclog_or_tty->print_cr("ThreadLocalAllocBuffer::compute_size(" SIZE_FORMAT ")" " returns failure", obj_size); } return 0; } if (PrintTLAB && Verbose) { gclog_or_tty->print_cr("ThreadLocalAllocBuffer::compute_size(" SIZE_FORMAT ")" " returns " SIZE_FORMAT, obj_size, new_tlab_size); } return new_tlab_size; }
/** * 根据统计信息调整当前线程的本地分配缓冲区的基准大小 */ void ThreadLocalAllocBuffer::resize() { if (ResizeTLAB) { //允许调整线程的本地分配缓冲区大小 // Compute the next tlab size using expected allocation amount size_t alloc = (size_t)(_allocation_fraction.average() * (Universe::heap()->tlab_capacity(myThread()) / HeapWordSize)); size_t new_size = alloc / _target_refills; //根据本地分配缓冲区大小允许的最大值/最小值来调整缓冲区的新大小 new_size = MIN2(MAX2(new_size, min_size()), max_size()); //内存对齐后的大小 size_t aligned_new_size = align_object_size(new_size); if (PrintTLAB && Verbose) { gclog_or_tty->print("TLAB new size: thread: " INTPTR_FORMAT " [id: %2d]" " refills %d alloc: %8.6f desired_size: " SIZE_FORMAT " -> " SIZE_FORMAT "\n", myThread(), myThread()->osthread()->thread_id(), _target_refills, _allocation_fraction.average(), desired_size(), aligned_new_size); } set_desired_size(aligned_new_size); set_refill_waste_limit(initial_refill_waste_limit()); } }
void ThreadLocalAllocBuffer::accumulate_statistics() { size_t capacity = Universe::heap()->tlab_capacity(myThread()) / HeapWordSize; size_t unused = Universe::heap()->unsafe_max_tlab_alloc(myThread()) / HeapWordSize; size_t used = capacity - unused; // Update allocation history if a reasonable amount of eden was allocated. bool update_allocation_history = used > 0.5 * capacity; _gc_waste += (unsigned)remaining(); if (PrintTLAB && (_number_of_refills > 0 || Verbose)) { print_stats("gc"); } if (_number_of_refills > 0) { if (update_allocation_history) { // Average the fraction of eden allocated in a tlab by this // thread for use in the next resize operation. // _gc_waste is not subtracted because it's included in // "used". size_t allocation = _number_of_refills * desired_size(); double alloc_frac = allocation / (double) used; _allocation_fraction.sample(alloc_frac); } global_stats()->update_allocating_threads(); global_stats()->update_number_of_refills(_number_of_refills); global_stats()->update_allocation(_number_of_refills * desired_size()); global_stats()->update_gc_waste(_gc_waste); global_stats()->update_slow_refill_waste(_slow_refill_waste); global_stats()->update_fast_refill_waste(_fast_refill_waste); } else { assert(_number_of_refills == 0 && _fast_refill_waste == 0 && _slow_refill_waste == 0 && _gc_waste == 0, "tlab stats == 0"); } global_stats()->update_slow_allocations(_slow_allocations); }
void ThreadLocalAllocBuffer::accumulate_statistics() { Thread* thread = myThread(); size_t capacity = Universe::heap()->tlab_capacity(thread); size_t used = Universe::heap()->tlab_used(thread); _gc_waste += (unsigned)remaining(); size_t total_allocated = thread->allocated_bytes(); size_t allocated_since_last_gc = total_allocated - _allocated_before_last_gc; _allocated_before_last_gc = total_allocated; if (PrintTLAB && (_number_of_refills > 0 || Verbose)) { print_stats("gc"); } if (_number_of_refills > 0) { // Update allocation history if a reasonable amount of eden was allocated. bool update_allocation_history = used > 0.5 * capacity; if (update_allocation_history) { // Average the fraction of eden allocated in a tlab by this // thread for use in the next resize operation. // _gc_waste is not subtracted because it's included in // "used". // The result can be larger than 1.0 due to direct to old allocations. // These allocations should ideally not be counted but since it is not possible // to filter them out here we just cap the fraction to be at most 1.0. double alloc_frac = MIN2(1.0, (double) allocated_since_last_gc / used); _allocation_fraction.sample(alloc_frac); } global_stats()->update_allocating_threads(); global_stats()->update_number_of_refills(_number_of_refills); global_stats()->update_allocation(_number_of_refills * desired_size()); global_stats()->update_gc_waste(_gc_waste); global_stats()->update_slow_refill_waste(_slow_refill_waste); global_stats()->update_fast_refill_waste(_fast_refill_waste); } else { assert(_number_of_refills == 0 && _fast_refill_waste == 0 && _slow_refill_waste == 0 && _gc_waste == 0, "tlab stats == 0"); } global_stats()->update_slow_allocations(_slow_allocations); }
void ThreadLocalAllocBuffer::resize() { // Compute the next tlab size using expected allocation amount assert(ResizeTLAB, "Should not call this otherwise"); size_t alloc = (size_t)(_allocation_fraction.average() * (Universe::heap()->tlab_capacity(myThread()) / HeapWordSize)); size_t new_size = alloc / _target_refills; new_size = MIN2(MAX2(new_size, min_size()), max_size()); size_t aligned_new_size = align_object_size(new_size); if (PrintTLAB && Verbose) { gclog_or_tty->print("TLAB new size: thread: " INTPTR_FORMAT " [id: %2d]" " refills %d alloc: %8.6f desired_size: " SIZE_FORMAT " -> " SIZE_FORMAT "\n", p2i(myThread()), myThread()->osthread()->thread_id(), _target_refills, _allocation_fraction.average(), desired_size(), aligned_new_size); } set_desired_size(aligned_new_size); set_refill_waste_limit(initial_refill_waste_limit()); }
void ThreadLocalAllocBuffer::initialize() { initialize(NULL, // start NULL, // top NULL); // end set_desired_size(initial_desired_size()); // Following check is needed because at startup the main (primordial) // thread is initialized before the heap is. The initialization for // this thread is redone in startup_initialization below. if (Universe::heap() != NULL) { size_t capacity = Universe::heap()->tlab_capacity(myThread()) / HeapWordSize; double alloc_frac = desired_size() * target_refills() / (double) capacity; _allocation_fraction.sample(alloc_frac); } set_refill_waste_limit(initial_refill_waste_limit()); initialize_statistics(); }
size_t initial_refill_waste_limit() { return desired_size() / TLABRefillWasteFraction; }