Commit 3f921372 authored by mlippautz's avatar mlippautz Committed by Commit bot

[heap] Non-contiguous young generation

This change removes the large contiguous backing store from the young generation
and replaces it regular pages.

We keep a pool of pages that are committed/uncommitted to avoid creating virtual
memory maps during growing and shrinking.

BUG=chromium:581412
LOG=N

Review URL: https://codereview.chromium.org/1853783002

Cr-Commit-Position: refs/heads/master@{#35261}
parent cf951dfb
......@@ -291,6 +291,10 @@ class VirtualMemory {
// by address().
VirtualMemory(size_t size, size_t alignment);
// Construct a virtual memory by assigning it some already mapped address
// and size.
VirtualMemory(void* address, size_t size) : address_(address), size_(size) {}
// Releases the reserved memory, if any, controlled by this VirtualMemory
// object.
~VirtualMemory();
......
......@@ -75,7 +75,6 @@ Heap::Heap()
code_range_size_(0),
// semispace_size_ should be a power of 2 and old_generation_size_ should
// be a multiple of Page::kPageSize.
reserved_semispace_size_(8 * (kPointerSize / 4) * MB),
max_semi_space_size_(8 * (kPointerSize / 4) * MB),
initial_semispace_size_(Page::kPageSize),
max_old_generation_size_(700ul * (kPointerSize / 4) * MB),
......@@ -4915,32 +4914,10 @@ bool Heap::ConfigureHeap(int max_semi_space_size, int max_old_space_size,
max_semi_space_size_ = Page::kPageSize;
}
if (isolate()->snapshot_available()) {
// If we are using a snapshot we always reserve the default amount
// of memory for each semispace because code in the snapshot has
// write-barrier code that relies on the size and alignment of new
// space. We therefore cannot use a larger max semispace size
// than the default reserved semispace size.
if (max_semi_space_size_ > reserved_semispace_size_) {
max_semi_space_size_ = reserved_semispace_size_;
if (FLAG_trace_gc) {
PrintIsolate(isolate_,
"Max semi-space size cannot be more than %d kbytes\n",
reserved_semispace_size_ >> 10);
}
}
} else {
// If we are not using snapshots we reserve space for the actual
// max semispace size.
reserved_semispace_size_ = max_semi_space_size_;
}
// The new space size must be a power of two to support single-bit testing
// for containment.
max_semi_space_size_ =
base::bits::RoundUpToPowerOfTwo32(max_semi_space_size_);
reserved_semispace_size_ =
base::bits::RoundUpToPowerOfTwo32(reserved_semispace_size_);
if (FLAG_min_semi_space_size > 0) {
int initial_semispace_size = FLAG_min_semi_space_size * MB;
......@@ -5284,7 +5261,7 @@ bool Heap::SetUp() {
incremental_marking_ = new IncrementalMarking(this);
// Set up new space.
if (!new_space_.SetUp(reserved_semispace_size_, max_semi_space_size_)) {
if (!new_space_.SetUp(initial_semispace_size_, max_semi_space_size_)) {
return false;
}
new_space_top_after_last_gc_ = new_space()->top();
......
......@@ -1174,16 +1174,11 @@ class Heap {
// GC statistics. ============================================================
// ===========================================================================
// Returns the maximum amount of memory reserved for the heap. For
// the young generation, we reserve 4 times the amount needed for a
// semi space. The young generation consists of two semi spaces and
// we reserve twice the amount needed for those in order to ensure
// that new space can be aligned to its size.
// Returns the maximum amount of memory reserved for the heap.
intptr_t MaxReserved() {
return 4 * reserved_semispace_size_ + max_old_generation_size_;
return 2 * max_semi_space_size_ + max_old_generation_size_;
}
int MaxSemiSpaceSize() { return max_semi_space_size_; }
int ReservedSemiSpaceSize() { return reserved_semispace_size_; }
int InitialSemiSpaceSize() { return initial_semispace_size_; }
intptr_t MaxOldGenerationSize() { return max_old_generation_size_; }
intptr_t MaxExecutableSize() { return max_executable_size_; }
......@@ -1995,10 +1990,8 @@ class Heap {
Object* roots_[kRootListLength];
size_t code_range_size_;
int reserved_semispace_size_;
int max_semi_space_size_;
int initial_semispace_size_;
int target_semispace_size_;
intptr_t max_old_generation_size_;
intptr_t initial_old_generation_size_;
bool old_generation_size_configured_;
......
......@@ -251,6 +251,19 @@ AllocationSpace AllocationResult::RetrySpace() {
return static_cast<AllocationSpace>(Smi::cast(object_)->value());
}
NewSpacePage* NewSpacePage::Initialize(Heap* heap, MemoryChunk* chunk,
Executability executable,
SemiSpace* owner) {
DCHECK_EQ(executable, Executability::NOT_EXECUTABLE);
bool in_to_space = (owner->id() != kFromSpace);
chunk->SetFlag(in_to_space ? MemoryChunk::IN_TO_SPACE
: MemoryChunk::IN_FROM_SPACE);
DCHECK(!chunk->IsFlagSet(in_to_space ? MemoryChunk::IN_FROM_SPACE
: MemoryChunk::IN_TO_SPACE));
NewSpacePage* page = static_cast<NewSpacePage*>(chunk);
heap->incremental_marking()->SetNewSpacePageFlags(page);
return page;
}
// --------------------------------------------------------------------------
// PagedSpace
......@@ -261,6 +274,7 @@ Page* Page::Initialize(Heap* heap, MemoryChunk* chunk, Executability executable,
page->mutex_ = new base::Mutex();
DCHECK(page->area_size() <= kAllocatableMemory);
DCHECK(chunk->owner() == owner);
owner->IncreaseCapacity(page->area_size());
heap->incremental_marking()->SetOldSpacePageFlags(chunk);
......
This diff is collapsed.
This diff is collapsed.
......@@ -2333,11 +2333,7 @@ TEST(GrowAndShrinkNewSpace) {
Heap* heap = CcTest::heap();
NewSpace* new_space = heap->new_space();
if (heap->ReservedSemiSpaceSize() == heap->InitialSemiSpaceSize() ||
heap->MaxSemiSpaceSize() == heap->InitialSemiSpaceSize()) {
// The max size cannot exceed the reserved size, since semispaces must be
// always within the reserved space. We can't test new space growing and
// shrinking if the reserved size is the same as the minimum (initial) size.
if (heap->MaxSemiSpaceSize() == heap->InitialSemiSpaceSize()) {
return;
}
......@@ -2382,11 +2378,7 @@ TEST(GrowAndShrinkNewSpace) {
TEST(CollectingAllAvailableGarbageShrinksNewSpace) {
CcTest::InitializeVM();
Heap* heap = CcTest::heap();
if (heap->ReservedSemiSpaceSize() == heap->InitialSemiSpaceSize() ||
heap->MaxSemiSpaceSize() == heap->InitialSemiSpaceSize()) {
// The max size cannot exceed the reserved size, since semispaces must be
// always within the reserved space. We can't test new space growing and
// shrinking if the reserved size is the same as the minimum (initial) size.
if (heap->MaxSemiSpaceSize() == heap->InitialSemiSpaceSize()) {
return;
}
......
......@@ -317,8 +317,9 @@ TEST(MemoryAllocator) {
{
int total_pages = 0;
OldSpace faked_space(heap, OLD_SPACE, NOT_EXECUTABLE);
Page* first_page = memory_allocator->AllocatePage(
faked_space.AreaSize(), &faked_space, NOT_EXECUTABLE);
Page* first_page = memory_allocator->AllocatePage<Page>(
faked_space.AreaSize(), static_cast<PagedSpace*>(&faked_space),
NOT_EXECUTABLE);
first_page->InsertAfter(faked_space.anchor()->prev_page());
CHECK(first_page->is_valid());
......@@ -330,8 +331,9 @@ TEST(MemoryAllocator) {
}
// Again, we should get n or n - 1 pages.
Page* other = memory_allocator->AllocatePage(faked_space.AreaSize(),
&faked_space, NOT_EXECUTABLE);
Page* other = memory_allocator->AllocatePage<Page>(
faked_space.AreaSize(), static_cast<PagedSpace*>(&faked_space),
NOT_EXECUTABLE);
CHECK(other->is_valid());
total_pages++;
other->InsertAfter(first_page);
......@@ -362,8 +364,8 @@ TEST(NewSpace) {
NewSpace new_space(heap);
CHECK(new_space.SetUp(CcTest::heap()->ReservedSemiSpaceSize(),
CcTest::heap()->ReservedSemiSpaceSize()));
CHECK(new_space.SetUp(CcTest::heap()->InitialSemiSpaceSize(),
CcTest::heap()->InitialSemiSpaceSize()));
CHECK(new_space.HasBeenSetUp());
while (new_space.Available() >= Page::kMaxRegularHeapObjectSize) {
......
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