# HG changeset patch # User jcoomes # Date 1329426833 28800 # Node ID 23c0eb012d6fc105477eb9f015ea8445247c026f # Parent ab4422d0ed596e67f2f20815bf085e075ffa99df 6330863: vm/gc/InfiniteList.java fails intermittently due to timeout Summary: in some cases, allocate from the old gen before doing a full gc Reviewed-by: stefank, jmasa diff -r ab4422d0ed59 -r 23c0eb012d6f src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp Thu Feb 16 13:12:25 2012 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp Thu Feb 16 13:13:53 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, 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 @@ -418,25 +418,17 @@ gc_count = Universe::heap()->total_collections(); result = young_gen()->allocate(size); - - // (1) If the requested object is too large to easily fit in the - // young_gen, or - // (2) If GC is locked out via GCLocker, young gen is full and - // the need for a GC already signalled to GCLocker (done - // at a safepoint), - // ... then, rather than force a safepoint and (a potentially futile) - // collection (attempt) for each allocation, try allocation directly - // in old_gen. For case (2) above, we may in the future allow - // TLAB allocation directly in the old gen. if (result != NULL) { return result; } - if (size >= (young_gen()->eden_space()->capacity_in_words(Thread::current()) / 2)) { - result = old_gen()->allocate(size); - if (result != NULL) { - return result; - } + + // If certain conditions hold, try allocating from the old gen. + result = mem_allocate_old_gen(size); + if (result != NULL) { + return result; } + + // Failed to allocate without a gc. if (GC_locker::is_active_and_needs_gc()) { // If this thread is not in a jni critical section, we stall // the requestor until the critical section has cleared and @@ -460,7 +452,6 @@ } if (result == NULL) { - // Generate a VM operation VM_ParallelGCFailedAllocation op(size, gc_count); VMThread::execute(&op); @@ -523,6 +514,42 @@ return result; } +// A "death march" is a series of ultra-slow allocations in which a full gc is +// done before each allocation, and after the full gc the allocation still +// cannot be satisfied from the young gen. This routine detects that condition; +// it should be called after a full gc has been done and the allocation +// attempted from the young gen. The parameter 'addr' should be the result of +// that young gen allocation attempt. +void +ParallelScavengeHeap::death_march_check(HeapWord* const addr, size_t size) { + if (addr != NULL) { + _death_march_count = 0; // death march has ended + } else if (_death_march_count == 0) { + if (should_alloc_in_eden(size)) { + _death_march_count = 1; // death march has started + } + } +} + +HeapWord* ParallelScavengeHeap::mem_allocate_old_gen(size_t size) { + if (!should_alloc_in_eden(size) || GC_locker::is_active_and_needs_gc()) { + // Size is too big for eden, or gc is locked out. + return old_gen()->allocate(size); + } + + // If a "death march" is in progress, allocate from the old gen a limited + // number of times before doing a GC. + if (_death_march_count > 0) { + if (_death_march_count < 64) { + ++_death_march_count; + return old_gen()->allocate(size); + } else { + _death_march_count = 0; + } + } + return NULL; +} + // Failed allocation policy. Must be called from the VM thread, and // only at a safepoint! Note that this method has policy for allocation // flow, and NOT collection policy. So we do not check for gc collection @@ -535,27 +562,22 @@ assert(!Universe::heap()->is_gc_active(), "not reentrant"); assert(!Heap_lock->owned_by_self(), "this thread should not own the Heap_lock"); - size_t mark_sweep_invocation_count = total_invocations(); - - // We assume (and assert!) that an allocation at this point will fail - // unless we collect. + // We assume that allocation in eden will fail unless we collect. // First level allocation failure, scavenge and allocate in young gen. GCCauseSetter gccs(this, GCCause::_allocation_failure); - PSScavenge::invoke(); + const bool invoked_full_gc = PSScavenge::invoke(); HeapWord* result = young_gen()->allocate(size); // Second level allocation failure. // Mark sweep and allocate in young generation. - if (result == NULL) { - // There is some chance the scavenge method decided to invoke mark_sweep. - // Don't mark sweep twice if so. - if (mark_sweep_invocation_count == total_invocations()) { - invoke_full_gc(false); - result = young_gen()->allocate(size); - } + if (result == NULL && !invoked_full_gc) { + invoke_full_gc(false); + result = young_gen()->allocate(size); } + death_march_check(result, size); + // Third level allocation failure. // After mark sweep and young generation allocation failure, // allocate in old generation. diff -r ab4422d0ed59 -r 23c0eb012d6f src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp Thu Feb 16 13:12:25 2012 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.hpp Thu Feb 16 13:13:53 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2012, 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 @@ -64,6 +64,7 @@ // Collection of generations that are adjacent in the // space reserved for the heap. AdjoiningGenerations* _gens; + unsigned int _death_march_count; static GCTaskManager* _gc_task_manager; // The task manager. @@ -71,8 +72,13 @@ static inline size_t total_invocations(); HeapWord* allocate_new_tlab(size_t size); + inline bool should_alloc_in_eden(size_t size) const; + inline void death_march_check(HeapWord* const result, size_t size); + HeapWord* mem_allocate_old_gen(size_t size); + public: ParallelScavengeHeap() : CollectedHeap() { + _death_march_count = 0; set_alignment(_perm_gen_alignment, intra_heap_alignment()); set_alignment(_young_gen_alignment, intra_heap_alignment()); set_alignment(_old_gen_alignment, intra_heap_alignment()); diff -r ab4422d0ed59 -r 23c0eb012d6f src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.inline.hpp --- a/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.inline.hpp Thu Feb 16 13:12:25 2012 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.inline.hpp Thu Feb 16 13:13:53 2012 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2012, 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 @@ -36,6 +36,12 @@ PSMarkSweep::total_invocations(); } +inline bool ParallelScavengeHeap::should_alloc_in_eden(const size_t size) const +{ + const size_t eden_size = young_gen()->eden_space()->capacity_in_words(); + return size < eden_size / 2; +} + inline void ParallelScavengeHeap::invoke_scavenge() { PSScavenge::invoke();