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;
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.
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();
}
}
}
// -----------------------------------------------------------------------------
// 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();
}
+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
return area_size_;
}
+ void CreateEmergencyMemory();
+ void FreeEmergencyMemory();
+ void UseEmergencyMemory();
+
+ bool HasEmergencyMemory() { return emergency_memory_ != NULL; }
+
protected:
FreeList* free_list() { return &free_list_; }
// 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.