From: kmillikin@chromium.org Date: Wed, 29 Oct 2008 09:27:59 +0000 (+0000) Subject: Check the growth of the old generation before expanding the paged X-Git-Tag: upstream/4.7.83~25088 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=af989d9e9416ff833d2abda43cf5d1d480fdb4ce;p=platform%2Fupstream%2Fv8.git Check the growth of the old generation before expanding the paged spaces (during normal allocation) and when allocating large objects. If the promotion limit is reached, fail allocation to trigger a garbage collection. Review URL: http://codereview.chromium.org/8657 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@632 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/heap.cc b/src/heap.cc index 14c1940..dc0e100 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -64,7 +64,12 @@ OldSpace* Heap::code_space_ = NULL; MapSpace* Heap::map_space_ = NULL; LargeObjectSpace* Heap::lo_space_ = NULL; -int Heap::promoted_space_limit_ = 0; +static const int kMinimumPromotionLimit = 2*MB; +static const int kMinimumAllocationLimit = 8*MB; + +int Heap::old_gen_promotion_limit_ = kMinimumPromotionLimit; +int Heap::old_gen_allocation_limit_ = kMinimumAllocationLimit; + int Heap::old_gen_exhausted_ = false; int Heap::amount_of_external_allocated_memory_ = 0; @@ -138,8 +143,7 @@ GarbageCollector Heap::SelectGarbageCollector(AllocationSpace space) { } // Is enough data promoted to justify a global GC? - if (PromotedSpaceSize() + PromotedExternalMemorySize() - > promoted_space_limit_) { + if (OldGenerationPromotionLimitReached()) { Counters::gc_compactor_caused_by_promoted_data.Increment(); return MARK_COMPACTOR; } @@ -360,9 +364,11 @@ void Heap::PerformGarbageCollection(AllocationSpace space, if (collector == MARK_COMPACTOR) { MarkCompact(tracer); - int promoted_space_size = PromotedSpaceSize(); - promoted_space_limit_ = - promoted_space_size + Max(2 * MB, (promoted_space_size/100) * 35); + int old_gen_size = PromotedSpaceSize(); + old_gen_promotion_limit_ = + old_gen_size + Max(kMinimumPromotionLimit, old_gen_size / 3); + old_gen_allocation_limit_ = + old_gen_size + Max(kMinimumAllocationLimit, old_gen_size / 3); old_gen_exhausted_ = false; // If we have used the mark-compact collector to collect the new @@ -2291,7 +2297,8 @@ void Heap::ReportHeapStatistics(const char* title) { PrintF(">>>>>> =============== %s (%d) =============== >>>>>>\n", title, gc_count_); PrintF("mark-compact GC : %d\n", mc_count_); - PrintF("promoted_space_limit_ %d\n", promoted_space_limit_); + PrintF("old_gen_promotion_limit_ %d\n", old_gen_promotion_limit_); + PrintF("old_gen_allocation_limit_ %d\n", old_gen_allocation_limit_); PrintF("\n"); PrintF("Number of handles : %d\n", HandleScope::NumberOfHandles()); diff --git a/src/heap.h b/src/heap.h index 87b972d..d120f5a 100644 --- a/src/heap.h +++ b/src/heap.h @@ -744,6 +744,20 @@ class Heap : public AllStatic { // Allocate unitialized fixed array (pretenure == NON_TENURE). static Object* AllocateRawFixedArray(int length); + // True if we have reached the allocation limit in the old generation that + // should force the next GC (caused normally) to be a full one. + static bool OldGenerationPromotionLimitReached() { + return (PromotedSpaceSize() + PromotedExternalMemorySize()) + > old_gen_promotion_limit_; + } + + // True if we have reached the allocation limit in the old generation that + // should artificially cause a GC right now. + static bool OldGenerationAllocationLimitReached() { + return (PromotedSpaceSize() + PromotedExternalMemorySize()) + > old_gen_allocation_limit_; + } + private: static int semispace_size_; static int initial_semispace_size_; @@ -785,8 +799,15 @@ class Heap : public AllStatic { static bool disallow_allocation_failure_; #endif // DEBUG - // Promotion limit that trigger a global GC - static int promoted_space_limit_; + // Limit that triggers a global GC on the next (normally caused) GC. This + // is checked when we have already decided to do a GC to help determine + // which collector to invoke. + static int old_gen_promotion_limit_; + + // Limit that triggers a global GC as soon as is reasonable. This is + // checked before expanding a paged space in the old generation and on + // every allocation in large object space. + static int old_gen_allocation_limit_; // The amount of external memory registered through the API kept alive // by global handles diff --git a/src/spaces.cc b/src/spaces.cc index 7894f24..34d27a7 100644 --- a/src/spaces.cc +++ b/src/spaces.cc @@ -1530,8 +1530,14 @@ HeapObject* OldSpace::SlowAllocateRaw(int size_in_bytes) { return HeapObject::cast(result); } - // Free list allocation failed and there is no next page. Try to expand - // the space and allocate in the new next page. + // Free list allocation failed and there is no next page. Fail if we have + // hit the old generation size limit that should cause a garbage + // collection. + if (Heap::OldGenerationAllocationLimitReached()) { + return NULL; + } + + // Try to expand the space and allocate in the new next page. ASSERT(!current_page->next_page()->is_valid()); if (Expand(current_page)) { return AllocateInNextPage(current_page, size_in_bytes); @@ -2009,8 +2015,14 @@ HeapObject* MapSpace::SlowAllocateRaw(int size_in_bytes) { } } - // Free list allocation failed and there is no next page. Try to expand - // the space and allocate in the new next page. + // Free list allocation failed and there is no next page. Fail if we have + // hit the old generation size limit that should cause a garbage + // collection. + if (Heap::OldGenerationAllocationLimitReached()) { + return NULL; + } + + // Try to expand the space and allocate in the new next page. ASSERT(!current_page->next_page()->is_valid()); if (Expand(current_page)) { return AllocateInNextPage(current_page, size_in_bytes); @@ -2236,6 +2248,13 @@ Object* LargeObjectSpace::AllocateRawInternal(int requested_size, int object_size, Executability executable) { ASSERT(0 < object_size && object_size <= requested_size); + + // Check if we want to force a GC before growing the old space further. + // If so, fail the allocation. + if (Heap::OldGenerationAllocationLimitReached()) { + return Failure::RetryAfterGC(requested_size, identity()); + } + size_t chunk_size; LargeObjectChunk* chunk = LargeObjectChunk::New(requested_size, &chunk_size, executable);