From f45afc557ea524c1022e3d4219cbfcb8f4c8090b Mon Sep 17 00:00:00 2001 From: "hpayer@chromium.org" Date: Wed, 30 Jul 2014 08:55:25 +0000 Subject: [PATCH] Use emergency memory in the case of out of memory during evacuation. BUG=395314 LOG=y R=jarin@chromium.org Review URL: https://codereview.chromium.org/431563002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22695 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/mark-compact.cc | 30 ++++++++++++++++++++++++++---- src/spaces.cc | 30 ++++++++++++++++++++++++++---- src/spaces.h | 12 ++++++++++++ 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/mark-compact.cc b/src/mark-compact.cc index 81361f0..f75db47 100644 --- a/src/mark-compact.cc +++ b/src/mark-compact.cc @@ -3106,6 +3106,12 @@ void MarkCompactCollector::EvacuateLiveObjectsFromPage(Page* p) { HeapObject* target_object; AllocationResult allocation = space->AllocateRaw(size); if (!allocation.To(&target_object)) { + // If allocation failed, use emergency memory and re-try allocation. + CHECK(space->HasEmergencyMemory()); + space->UseEmergencyMemory(); + allocation = space->AllocateRaw(size); + } + if (!allocation.To(&target_object)) { // OS refused to give us memory. V8::FatalProcessOutOfMemory("Evacuation"); return; @@ -3130,10 +3136,16 @@ void MarkCompactCollector::EvacuatePages() { p->IsFlagSet(Page::RESCAN_ON_EVACUATION)); ASSERT(static_cast(p->parallel_sweeping()) == MemoryChunk::SWEEPING_DONE); + PagedSpace* space = static_cast(p->owner()); + // Allocate emergency memory for the case when compaction fails due to out + // of memory. + if (!space->HasEmergencyMemory()) { + space->CreateEmergencyMemory(); + } if (p->IsEvacuationCandidate()) { - // During compaction we might have to request a new page. - // Check that space still have room for that. - if (static_cast(p->owner())->CanExpand()) { + // During compaction we might have to request a new page. Check that we + // have an emergency page and the space still has room for that. + if (space->HasEmergencyMemory() && space->CanExpand()) { EvacuateLiveObjectsFromPage(p); } else { // Without room for expansion evacuation is not guaranteed to succeed. @@ -3144,7 +3156,17 @@ void MarkCompactCollector::EvacuatePages() { page->ClearEvacuationCandidate(); page->SetFlag(Page::RESCAN_ON_EVACUATION); } - return; + break; + } + } + } + if (npages > 0) { + // Release emergency memory. + PagedSpaces spaces(heap()); + for (PagedSpace* space = spaces.next(); space != NULL; + space = spaces.next()) { + if (space->HasEmergencyMemory()) { + space->FreeEmergencyMemory(); } } } diff --git a/src/spaces.cc b/src/spaces.cc index 4826ef0..76b929d 100644 --- a/src/spaces.cc +++ b/src/spaces.cc @@ -929,15 +929,14 @@ void MemoryChunk::IncrementLiveBytesFromMutator(Address address, int by) { // ----------------------------------------------------------------------------- // PagedSpace implementation -PagedSpace::PagedSpace(Heap* heap, - intptr_t max_capacity, - AllocationSpace id, +PagedSpace::PagedSpace(Heap* heap, intptr_t max_capacity, AllocationSpace id, Executability executable) : Space(heap, id, executable), free_list_(this), swept_precisely_(true), unswept_free_bytes_(0), - end_of_unswept_pages_(NULL) { + end_of_unswept_pages_(NULL), + emergency_memory_(NULL) { if (id == CODE_SPACE) { area_size_ = heap->isolate()->memory_allocator()-> CodePageAreaSize(); @@ -1150,6 +1149,29 @@ void PagedSpace::ReleasePage(Page* page) { } +void PagedSpace::CreateEmergencyMemory() { + emergency_memory_ = heap()->isolate()->memory_allocator()->AllocateChunk( + AreaSize(), AreaSize(), executable(), this); +} + + +void PagedSpace::FreeEmergencyMemory() { + Page* page = static_cast(emergency_memory_); + ASSERT(page->LiveBytes() == 0); + ASSERT(AreaSize() == page->area_size()); + ASSERT(!free_list_.ContainsPageFreeListItems(page)); + heap()->isolate()->memory_allocator()->Free(page); + emergency_memory_ = NULL; +} + + +void PagedSpace::UseEmergencyMemory() { + Page* page = Page::Initialize(heap(), emergency_memory_, executable(), this); + page->InsertAfter(anchor_.prev_page()); + emergency_memory_ = NULL; +} + + #ifdef DEBUG void PagedSpace::Print() { } #endif diff --git a/src/spaces.h b/src/spaces.h index 3fe71b2..b8fa8c7 100644 --- a/src/spaces.h +++ b/src/spaces.h @@ -1980,6 +1980,12 @@ class PagedSpace : public Space { return area_size_; } + void CreateEmergencyMemory(); + void FreeEmergencyMemory(); + void UseEmergencyMemory(); + + bool HasEmergencyMemory() { return emergency_memory_ != NULL; } + protected: FreeList* free_list() { return &free_list_; } @@ -2015,6 +2021,12 @@ class PagedSpace : public Space { // end_of_unswept_pages_ page. Page* end_of_unswept_pages_; + // Emergency memory is the memory of a full page for a given space, allocated + // conservatively before evacuating a page. If compaction fails due to out + // of memory error the emergency memory can be used to complete compaction. + // If not used, the emergency memory is released after compaction. + MemoryChunk* emergency_memory_; + // Expands the space by allocating a fixed number of pages. Returns false if // it cannot allocate requested number of pages from OS, or if the hard heap // size limit has been hit. -- 2.7.4