Commit f45afc55 authored by hpayer@chromium.org's avatar hpayer@chromium.org

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
parent 39f82ac3
......@@ -3105,6 +3105,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");
......@@ -3130,10 +3136,16 @@ void MarkCompactCollector::EvacuatePages() {
p->IsFlagSet(Page::RESCAN_ON_EVACUATION));
ASSERT(static_cast<int>(p->parallel_sweeping()) ==
MemoryChunk::SWEEPING_DONE);
PagedSpace* space = static_cast<PagedSpace*>(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<PagedSpace*>(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();
}
}
}
......
......@@ -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<Page*>(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
......
......@@ -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.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment