[api] Add a way to specify the max heap size in ResourceConstraints
The new API function is called ConfigureDefaultsFromHeapSize and accepts two parameters: the initial and the maximum heap size. Based on the given limits the function computes the default size for the young and the old generation. The patch also cleans up the existing functions to make them consistent in terms of units and heap structure. Bug: v8:9306 Change-Id: If2200a9cdb45b0b818a373207efe4e6426f7b688 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1631593 Commit-Queue: Ulan Degenbaev <ulan@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Michael Lippautz <mlippautz@chromium.org> Cr-Commit-Position: refs/heads/master@{#62017}
This commit is contained in:
parent
ea79fa426d
commit
e423f00403
121
include/v8.h
121
include/v8.h
@ -6405,7 +6405,19 @@ V8_INLINE Local<Boolean> False(Isolate* isolate);
|
||||
*/
|
||||
class V8_EXPORT ResourceConstraints {
|
||||
public:
|
||||
ResourceConstraints();
|
||||
/**
|
||||
* Configures the constraints with reasonable default values based on the
|
||||
* provided heap size limit. The heap size includes both the young and
|
||||
* the old generation.
|
||||
*
|
||||
* \param maximum_heap_size_in_bytes The hard limit for the heap size.
|
||||
* When the heap size approaches this limit, V8 will perform series of
|
||||
* garbage collections and invoke the NearHeapLimitCallback.
|
||||
* If the garbage collections do not help and the callback does not
|
||||
* increase the limit, then V8 will crash with V8::FatalProcessOutOfMemory.
|
||||
*/
|
||||
void ConfigureDefaultsFromHeapSize(size_t initial_heap_size_in_bytes,
|
||||
size_t maximum_heap_size_in_bytes);
|
||||
|
||||
/**
|
||||
* Configures the constraints with reasonable default values based on the
|
||||
@ -6419,26 +6431,81 @@ class V8_EXPORT ResourceConstraints {
|
||||
void ConfigureDefaults(uint64_t physical_memory,
|
||||
uint64_t virtual_memory_limit);
|
||||
|
||||
// Returns the max semi-space size in KB.
|
||||
size_t max_semi_space_size_in_kb() const {
|
||||
return max_semi_space_size_in_kb_;
|
||||
}
|
||||
|
||||
// Sets the max semi-space size in KB.
|
||||
void set_max_semi_space_size_in_kb(size_t limit_in_kb) {
|
||||
max_semi_space_size_in_kb_ = limit_in_kb;
|
||||
}
|
||||
|
||||
size_t max_old_space_size() const { return max_old_space_size_; }
|
||||
void set_max_old_space_size(size_t limit_in_mb) {
|
||||
max_old_space_size_ = limit_in_mb;
|
||||
}
|
||||
/**
|
||||
* The address beyond which the VM's stack may not grow.
|
||||
*/
|
||||
uint32_t* stack_limit() const { return stack_limit_; }
|
||||
// Sets an address beyond which the VM's stack may not grow.
|
||||
void set_stack_limit(uint32_t* value) { stack_limit_ = value; }
|
||||
size_t code_range_size() const { return code_range_size_; }
|
||||
void set_code_range_size(size_t limit_in_mb) {
|
||||
code_range_size_ = limit_in_mb;
|
||||
|
||||
/**
|
||||
* The amount of virtual memory reserved for generated code. This is relevant
|
||||
* for 64-bit architectures that rely on code range for calls in code.
|
||||
*/
|
||||
size_t code_range_size_in_bytes() const { return code_range_size_; }
|
||||
void set_code_range_size_in_bytes(size_t limit) { code_range_size_ = limit; }
|
||||
|
||||
/**
|
||||
* The maximum size of the old generation.
|
||||
* When the old generation approaches this limit, V8 will perform series of
|
||||
* garbage collections and invoke the NearHeapLimitCallback.
|
||||
* If the garbage collections do not help and the callback does not
|
||||
* increase the limit, then V8 will crash with V8::FatalProcessOutOfMemory.
|
||||
*/
|
||||
size_t max_old_generation_size_in_bytes() const {
|
||||
return max_old_generation_size_;
|
||||
}
|
||||
void set_max_old_generation_size_in_bytes(size_t limit) {
|
||||
max_old_generation_size_ = limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* The maximum size of the young generation, which consists of two semi-spaces
|
||||
* and a large object space. This affects frequency of Scavenge garbage
|
||||
* collections and should be typically much smaller that the old generation.
|
||||
*/
|
||||
size_t max_young_generation_size_in_bytes() const {
|
||||
return max_young_generation_size_;
|
||||
}
|
||||
void set_max_young_generation_size_in_bytes(size_t limit) {
|
||||
max_young_generation_size_ = limit;
|
||||
}
|
||||
|
||||
size_t initial_old_generation_size_in_bytes() const {
|
||||
return initial_old_generation_size_;
|
||||
}
|
||||
void set_initial_old_generation_size_in_bytes(size_t initial_size) {
|
||||
initial_old_generation_size_ = initial_size;
|
||||
}
|
||||
|
||||
size_t initial_young_generation_size_in_bytes() const {
|
||||
return initial_young_generation_size_;
|
||||
}
|
||||
void set_initial_young_generation_size_in_bytes(size_t initial_size) {
|
||||
initial_young_generation_size_ = initial_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated functions. Do not use in new code.
|
||||
*/
|
||||
V8_DEPRECATE_SOON("Use code_range_size_in_bytes.",
|
||||
size_t code_range_size() const) {
|
||||
return code_range_size_ / kMB;
|
||||
}
|
||||
V8_DEPRECATE_SOON("Use set_code_range_size_in_bytes.",
|
||||
void set_code_range_size(size_t limit_in_mb)) {
|
||||
code_range_size_ = limit_in_mb * kMB;
|
||||
}
|
||||
V8_DEPRECATE_SOON("Use max_young_generation_size_in_bytes.",
|
||||
size_t max_semi_space_size_in_kb() const);
|
||||
V8_DEPRECATE_SOON("Use set_max_young_generation_size_in_bytes.",
|
||||
void set_max_semi_space_size_in_kb(size_t limit_in_kb));
|
||||
V8_DEPRECATE_SOON("Use max_old_generation_size_in_bytes.",
|
||||
size_t max_old_space_size() const) {
|
||||
return max_old_generation_size_ / kMB;
|
||||
}
|
||||
V8_DEPRECATE_SOON("Use set_max_old_generation_size_in_bytes.",
|
||||
void set_max_old_space_size(size_t limit_in_mb)) {
|
||||
max_old_generation_size_ = limit_in_mb * kMB;
|
||||
}
|
||||
V8_DEPRECATE_SOON("Zone does not pool memory any more.",
|
||||
size_t max_zone_pool_size() const) {
|
||||
@ -6450,14 +6517,14 @@ class V8_EXPORT ResourceConstraints {
|
||||
}
|
||||
|
||||
private:
|
||||
// max_semi_space_size_ is in KB
|
||||
size_t max_semi_space_size_in_kb_;
|
||||
|
||||
// The remaining limits are in MB
|
||||
size_t max_old_space_size_;
|
||||
uint32_t* stack_limit_;
|
||||
size_t code_range_size_;
|
||||
size_t max_zone_pool_size_;
|
||||
static constexpr size_t kMB = 1048576u;
|
||||
size_t code_range_size_ = 0;
|
||||
size_t max_old_generation_size_ = 0;
|
||||
size_t max_young_generation_size_ = 0;
|
||||
size_t max_zone_pool_size_ = 0;
|
||||
size_t initial_old_generation_size_ = 0;
|
||||
size_t initial_young_generation_size_ = 0;
|
||||
uint32_t* stack_limit_ = nullptr;
|
||||
};
|
||||
|
||||
|
||||
|
@ -963,30 +963,59 @@ Extension::Extension(const char* name, const char* source, int dep_count,
|
||||
CHECK(source != nullptr || source_length_ == 0);
|
||||
}
|
||||
|
||||
ResourceConstraints::ResourceConstraints()
|
||||
: max_semi_space_size_in_kb_(0),
|
||||
max_old_space_size_(0),
|
||||
stack_limit_(nullptr),
|
||||
code_range_size_(0),
|
||||
max_zone_pool_size_(0) {}
|
||||
void ResourceConstraints::ConfigureDefaultsFromHeapSize(
|
||||
size_t initial_heap_size_in_bytes, size_t maximum_heap_size_in_bytes) {
|
||||
CHECK_LE(initial_heap_size_in_bytes, maximum_heap_size_in_bytes);
|
||||
if (maximum_heap_size_in_bytes == 0) {
|
||||
return;
|
||||
}
|
||||
size_t young_generation, old_generation;
|
||||
i::Heap::GenerationSizesFromHeapSize(maximum_heap_size_in_bytes,
|
||||
&young_generation, &old_generation);
|
||||
set_max_young_generation_size_in_bytes(
|
||||
i::Max(young_generation, i::Heap::MinYoungGenerationSize()));
|
||||
set_max_old_generation_size_in_bytes(
|
||||
i::Max(old_generation, i::Heap::MinOldGenerationSize()));
|
||||
if (initial_heap_size_in_bytes > 0) {
|
||||
i::Heap::GenerationSizesFromHeapSize(initial_heap_size_in_bytes,
|
||||
&young_generation, &old_generation);
|
||||
// We do not set lower bounds for the initial sizes.
|
||||
set_initial_young_generation_size_in_bytes(young_generation);
|
||||
set_initial_old_generation_size_in_bytes(old_generation);
|
||||
}
|
||||
if (i::kRequiresCodeRange) {
|
||||
set_code_range_size_in_bytes(
|
||||
i::Min(i::kMaximalCodeRangeSize, maximum_heap_size_in_bytes));
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceConstraints::ConfigureDefaults(uint64_t physical_memory,
|
||||
uint64_t virtual_memory_limit) {
|
||||
size_t old_space_size, semi_space_size;
|
||||
i::Heap::ComputeMaxSpaceSizes(physical_memory, &old_space_size,
|
||||
&semi_space_size);
|
||||
set_max_semi_space_size_in_kb(semi_space_size / i::KB);
|
||||
set_max_old_space_size(old_space_size / i::MB);
|
||||
size_t heap_size = i::Heap::HeapSizeFromPhysicalMemory(physical_memory);
|
||||
size_t young_generation, old_generation;
|
||||
i::Heap::GenerationSizesFromHeapSize(heap_size, &young_generation,
|
||||
&old_generation);
|
||||
set_max_young_generation_size_in_bytes(young_generation);
|
||||
set_max_old_generation_size_in_bytes(old_generation);
|
||||
|
||||
if (virtual_memory_limit > 0 && i::kRequiresCodeRange) {
|
||||
// Reserve no more than 1/8 of the memory for the code range, but at most
|
||||
// kMaximalCodeRangeSize.
|
||||
set_code_range_size(
|
||||
i::Min(i::kMaximalCodeRangeSize / i::MB,
|
||||
static_cast<size_t>((virtual_memory_limit >> 3) / i::MB)));
|
||||
set_code_range_size_in_bytes(
|
||||
i::Min(i::kMaximalCodeRangeSize,
|
||||
static_cast<size_t>(virtual_memory_limit / 8)));
|
||||
}
|
||||
}
|
||||
|
||||
size_t ResourceConstraints::max_semi_space_size_in_kb() const {
|
||||
return i::Heap::SemiSpaceSizeFromYoungGenerationSize(
|
||||
max_young_generation_size_) /
|
||||
i::KB;
|
||||
}
|
||||
|
||||
void ResourceConstraints::set_max_semi_space_size_in_kb(size_t limit_in_kb) {
|
||||
set_max_young_generation_size_in_bytes(
|
||||
i::Heap::YoungGenerationSizeFromSemiSpaceSize(limit_in_kb * i::KB));
|
||||
}
|
||||
|
||||
i::Address* V8::GlobalizeReference(i::Isolate* isolate, i::Address* obj) {
|
||||
LOG_API(isolate, Persistent, New);
|
||||
i::Handle<i::Object> result = isolate->global_handles()->Create(*obj);
|
||||
|
125
src/heap/heap.cc
125
src/heap/heap.cc
@ -207,13 +207,69 @@ size_t Heap::MaxReserved() {
|
||||
max_old_generation_size_);
|
||||
}
|
||||
|
||||
void Heap::ComputeMaxSpaceSizes(uint64_t physical_memory,
|
||||
size_t* old_space_size,
|
||||
size_t* semi_space_size) {
|
||||
// Compute the old space size and cap it.
|
||||
uint64_t old_space =
|
||||
physical_memory / kPhysicalMemoryToOldSpaceRatio * kPointerMultiplier;
|
||||
uint64_t max_size = V8HeapTrait::kMaxSize;
|
||||
size_t Heap::YoungGenerationSizeFromOldGenerationSize(size_t old_generation) {
|
||||
// Compute the semi space size and cap it.
|
||||
size_t ratio = old_generation <= kOldGenerationLowMemory
|
||||
? kOldGenerationToSemiSpaceRatioLowMemory
|
||||
: kOldGenerationToSemiSpaceRatio;
|
||||
size_t semi_space = old_generation / ratio;
|
||||
semi_space = Min<size_t>(semi_space, kMaxSemiSpaceSize);
|
||||
semi_space = Max<size_t>(semi_space, kMinSemiSpaceSize);
|
||||
semi_space = RoundUp(semi_space, Page::kPageSize);
|
||||
return YoungGenerationSizeFromSemiSpaceSize(semi_space);
|
||||
}
|
||||
|
||||
size_t Heap::HeapSizeFromPhysicalMemory(uint64_t physical_memory) {
|
||||
// Compute the old generation size and cap it.
|
||||
uint64_t old_generation = physical_memory /
|
||||
kPhysicalMemoryToOldGenerationRatio *
|
||||
kPointerMultiplier;
|
||||
old_generation =
|
||||
Min<uint64_t>(old_generation, MaxOldGenerationSize(physical_memory));
|
||||
old_generation = Max<uint64_t>(old_generation, V8HeapTrait::kMinSize);
|
||||
old_generation = RoundUp(old_generation, Page::kPageSize);
|
||||
|
||||
size_t young_generation = YoungGenerationSizeFromOldGenerationSize(
|
||||
static_cast<size_t>(old_generation));
|
||||
return static_cast<size_t>(old_generation) + young_generation;
|
||||
}
|
||||
|
||||
void Heap::GenerationSizesFromHeapSize(size_t heap_size,
|
||||
size_t* young_generation_size,
|
||||
size_t* old_generation_size) {
|
||||
// Initialize values for the case when the given heap size is too small.
|
||||
*young_generation_size = 0;
|
||||
*old_generation_size = 0;
|
||||
// Binary search for the largest old generation size that fits to the given
|
||||
// heap limit considering the correspondingly sized young generation.
|
||||
size_t lower = 0, upper = heap_size;
|
||||
while (lower + 1 < upper) {
|
||||
size_t old_generation = lower + (upper - lower) / 2;
|
||||
size_t young_generation =
|
||||
YoungGenerationSizeFromOldGenerationSize(old_generation);
|
||||
if (old_generation + young_generation <= heap_size) {
|
||||
// This size configuration fits into the given heap limit.
|
||||
*young_generation_size = young_generation;
|
||||
*old_generation_size = old_generation;
|
||||
lower = old_generation;
|
||||
} else {
|
||||
upper = old_generation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t Heap::MinYoungGenerationSize() {
|
||||
return YoungGenerationSizeFromSemiSpaceSize(kMinSemiSpaceSize);
|
||||
}
|
||||
|
||||
size_t Heap::MinOldGenerationSize() {
|
||||
size_t paged_space_count =
|
||||
LAST_GROWABLE_PAGED_SPACE - FIRST_GROWABLE_PAGED_SPACE + 1;
|
||||
return paged_space_count * Page::kPageSize;
|
||||
}
|
||||
|
||||
size_t Heap::MaxOldGenerationSize(uint64_t physical_memory) {
|
||||
size_t max_size = V8HeapTrait::kMaxSize;
|
||||
// Finch experiment: Increase the heap size from 2GB to 4GB for 64-bit
|
||||
// systems with physical memory bigger than 16GB.
|
||||
constexpr bool x64_bit = Heap::kPointerMultiplier >= 2;
|
||||
@ -222,22 +278,16 @@ void Heap::ComputeMaxSpaceSizes(uint64_t physical_memory,
|
||||
DCHECK_EQ(max_size / GB, 2);
|
||||
max_size *= 2;
|
||||
}
|
||||
old_space = Min<uint64_t>(old_space, max_size);
|
||||
old_space = Max<uint64_t>(old_space, V8HeapTrait::kMinSize);
|
||||
old_space = RoundUp(old_space, Page::kPageSize);
|
||||
return max_size;
|
||||
}
|
||||
|
||||
// Compute the semi space size and cap it.
|
||||
size_t ratio = physical_memory <= kLowMemory
|
||||
? kOldSpaceToSemiSpaceRatioLowMemory
|
||||
: kOldSpaceToSemiSpaceRatio;
|
||||
uint64_t semi_space = old_space / ratio;
|
||||
semi_space = Min<uint64_t>(semi_space, kMaxSemiSpaceSize);
|
||||
semi_space = Max<uint64_t>(semi_space, kMinSemiSpaceSize);
|
||||
semi_space = RoundUp(semi_space, Page::kPageSize);
|
||||
size_t Heap::YoungGenerationSizeFromSemiSpaceSize(size_t semi_space_size) {
|
||||
return semi_space_size * (2 + kNewLargeObjectSpaceToSemiSpaceRatio);
|
||||
}
|
||||
|
||||
// Write the results back.
|
||||
*old_space_size = static_cast<size_t>(old_space);
|
||||
*semi_space_size = static_cast<size_t>(semi_space);
|
||||
size_t Heap::SemiSpaceSizeFromYoungGenerationSize(
|
||||
size_t young_generation_size) {
|
||||
return young_generation_size / (2 + kNewLargeObjectSpaceToSemiSpaceRatio);
|
||||
}
|
||||
|
||||
size_t Heap::Capacity() {
|
||||
@ -325,7 +375,7 @@ size_t Heap::Available() {
|
||||
|
||||
bool Heap::CanExpandOldGeneration(size_t size) {
|
||||
if (force_oom_) return false;
|
||||
if (OldGenerationCapacity() + size > MaxOldGenerationSize()) return false;
|
||||
if (OldGenerationCapacity() + size > max_old_generation_size_) return false;
|
||||
// The OldGenerationCapacity does not account compaction spaces used
|
||||
// during evacuation. Ensure that expanding the old generation does push
|
||||
// the total allocated memory size over the maximum heap size.
|
||||
@ -1288,7 +1338,8 @@ void Heap::CollectAllAvailableGarbage(GarbageCollectionReason gc_reason) {
|
||||
|
||||
set_current_gc_flags(kNoGCFlags);
|
||||
new_space_->Shrink();
|
||||
new_lo_space_->SetCapacity(new_space_->Capacity());
|
||||
new_lo_space_->SetCapacity(new_space_->Capacity() *
|
||||
kNewLargeObjectSpaceToSemiSpaceRatio);
|
||||
UncommitFromSpace();
|
||||
EagerlyFreeExternalMemory();
|
||||
|
||||
@ -4276,14 +4327,12 @@ void Heap::IterateBuiltins(RootVisitor* v) {
|
||||
#endif // V8_EMBEDDED_BUILTINS
|
||||
}
|
||||
|
||||
// TODO(1236194): Since the heap size is configurable on the command line
|
||||
// and through the API, we should gracefully handle the case that the heap
|
||||
// size is not big enough to fit all the initial objects.
|
||||
void Heap::ConfigureHeap(const v8::ResourceConstraints& constraints) {
|
||||
// Initialize max_semi_space_size_.
|
||||
{
|
||||
if (constraints.max_semi_space_size_in_kb() > 0) {
|
||||
max_semi_space_size_ = constraints.max_semi_space_size_in_kb() * KB;
|
||||
if (constraints.max_young_generation_size_in_bytes() > 0) {
|
||||
max_semi_space_size_ = SemiSpaceSizeFromYoungGenerationSize(
|
||||
constraints.max_young_generation_size_in_bytes());
|
||||
}
|
||||
if (FLAG_max_semi_space_size > 0) {
|
||||
max_semi_space_size_ = static_cast<size_t>(FLAG_max_semi_space_size) * MB;
|
||||
@ -4304,18 +4353,15 @@ void Heap::ConfigureHeap(const v8::ResourceConstraints& constraints) {
|
||||
|
||||
// Initialize max_old_generation_size_.
|
||||
{
|
||||
if (constraints.max_old_space_size() > 0) {
|
||||
max_old_generation_size_ = constraints.max_old_space_size() * MB;
|
||||
if (constraints.max_old_generation_size_in_bytes() > 0) {
|
||||
max_old_generation_size_ = constraints.max_old_generation_size_in_bytes();
|
||||
}
|
||||
if (FLAG_max_old_space_size > 0) {
|
||||
max_old_generation_size_ =
|
||||
static_cast<size_t>(FLAG_max_old_space_size) * MB;
|
||||
}
|
||||
int paged_space_count =
|
||||
LAST_GROWABLE_PAGED_SPACE - FIRST_GROWABLE_PAGED_SPACE + 1;
|
||||
max_old_generation_size_ =
|
||||
Max(max_old_generation_size_,
|
||||
static_cast<size_t>(paged_space_count * Page::kPageSize));
|
||||
Max(max_old_generation_size_, MinOldGenerationSize());
|
||||
max_old_generation_size_ =
|
||||
RoundDown<Page::kPageSize>(max_old_generation_size_);
|
||||
}
|
||||
@ -4327,6 +4373,10 @@ void Heap::ConfigureHeap(const v8::ResourceConstraints& constraints) {
|
||||
initial_semispace_size_ =
|
||||
Max(initial_semispace_size_, static_cast<size_t>(1 * MB));
|
||||
}
|
||||
if (constraints.initial_young_generation_size_in_bytes() > 0) {
|
||||
initial_semispace_size_ = SemiSpaceSizeFromYoungGenerationSize(
|
||||
constraints.initial_young_generation_size_in_bytes());
|
||||
}
|
||||
if (FLAG_min_semi_space_size > 0) {
|
||||
initial_semispace_size_ =
|
||||
static_cast<size_t>(FLAG_min_semi_space_size) * MB;
|
||||
@ -4340,6 +4390,11 @@ void Heap::ConfigureHeap(const v8::ResourceConstraints& constraints) {
|
||||
// Initialize initial_old_space_size_.
|
||||
{
|
||||
initial_old_generation_size_ = kMaxInitialOldGenerationSize;
|
||||
if (constraints.initial_old_generation_size_in_bytes() > 0) {
|
||||
initial_old_generation_size_ =
|
||||
constraints.initial_old_generation_size_in_bytes();
|
||||
old_generation_size_configured_ = true;
|
||||
}
|
||||
if (FLAG_initial_old_space_size > 0) {
|
||||
initial_old_generation_size_ =
|
||||
static_cast<size_t>(FLAG_initial_old_space_size) * MB;
|
||||
@ -4364,7 +4419,7 @@ void Heap::ConfigureHeap(const v8::ResourceConstraints& constraints) {
|
||||
FixedArray::SizeFor(JSArray::kInitialMaxFastElementArray) +
|
||||
AllocationMemento::kSize));
|
||||
|
||||
code_range_size_ = constraints.code_range_size() * MB;
|
||||
code_range_size_ = constraints.code_range_size_in_bytes();
|
||||
|
||||
configured_ = true;
|
||||
}
|
||||
|
@ -251,12 +251,14 @@ class Heap {
|
||||
256 * MB * kPointerMultiplier;
|
||||
|
||||
// These constants control heap configuration based on the physical memory.
|
||||
static const size_t kPhysicalMemoryToOldSpaceRatio = 4;
|
||||
static const size_t kOldSpaceToSemiSpaceRatio = 128;
|
||||
static const size_t kOldSpaceToSemiSpaceRatioLowMemory = 256;
|
||||
static const size_t kLowMemory = 512 * MB;
|
||||
static const size_t kMinSemiSpaceSize = 512 * KB * kPointerMultiplier;
|
||||
static const size_t kMaxSemiSpaceSize = 8192 * KB * kPointerMultiplier;
|
||||
static constexpr size_t kPhysicalMemoryToOldGenerationRatio = 4;
|
||||
static constexpr size_t kOldGenerationToSemiSpaceRatio = 128;
|
||||
static constexpr size_t kOldGenerationToSemiSpaceRatioLowMemory = 256;
|
||||
static constexpr size_t kOldGenerationLowMemory =
|
||||
128 * MB * kPointerMultiplier;
|
||||
static constexpr size_t kNewLargeObjectSpaceToSemiSpaceRatio = 1;
|
||||
static constexpr size_t kMinSemiSpaceSize = 512 * KB * kPointerMultiplier;
|
||||
static constexpr size_t kMaxSemiSpaceSize = 8192 * KB * kPointerMultiplier;
|
||||
|
||||
STATIC_ASSERT(kMinSemiSpaceSize % (1 << kPageSizeBits) == 0);
|
||||
STATIC_ASSERT(kMaxSemiSpaceSize % (1 << kPageSizeBits) == 0);
|
||||
@ -575,7 +577,7 @@ class Heap {
|
||||
// For post mortem debugging.
|
||||
void RememberUnmappedPage(Address page, bool compacted);
|
||||
|
||||
int64_t external_memory_hard_limit() { return MaxOldGenerationSize() / 2; }
|
||||
int64_t external_memory_hard_limit() { return max_old_generation_size_ / 2; }
|
||||
|
||||
V8_INLINE int64_t external_memory();
|
||||
V8_INLINE void update_external_memory(int64_t delta);
|
||||
@ -1041,9 +1043,21 @@ class Heap {
|
||||
size_t InitialSemiSpaceSize() { return initial_semispace_size_; }
|
||||
size_t MaxOldGenerationSize() { return max_old_generation_size_; }
|
||||
|
||||
V8_EXPORT_PRIVATE static void ComputeMaxSpaceSizes(uint64_t physical_memory,
|
||||
size_t* old_space_size,
|
||||
size_t* semi_space_size);
|
||||
V8_EXPORT_PRIVATE static size_t HeapSizeFromPhysicalMemory(
|
||||
uint64_t physical_memory);
|
||||
V8_EXPORT_PRIVATE static void GenerationSizesFromHeapSize(
|
||||
size_t heap_size, size_t* young_generation_size,
|
||||
size_t* old_generation_size);
|
||||
V8_EXPORT_PRIVATE static size_t YoungGenerationSizeFromOldGenerationSize(
|
||||
size_t old_generation_size);
|
||||
V8_EXPORT_PRIVATE static size_t YoungGenerationSizeFromSemiSpaceSize(
|
||||
size_t semi_space_size);
|
||||
V8_EXPORT_PRIVATE static size_t SemiSpaceSizeFromYoungGenerationSize(
|
||||
size_t young_generation_size);
|
||||
V8_EXPORT_PRIVATE static size_t MinYoungGenerationSize();
|
||||
V8_EXPORT_PRIVATE static size_t MinOldGenerationSize();
|
||||
V8_EXPORT_PRIVATE static size_t MaxOldGenerationSize(
|
||||
uint64_t physical_memory);
|
||||
|
||||
// Returns the capacity of the heap in bytes w/o growing. Heap grows when
|
||||
// more spaces are needed until it reaches the limit.
|
||||
|
@ -259,13 +259,13 @@ int main(int argc, char** argv) {
|
||||
// Set code range such that relative jumps for builtins to
|
||||
// builtin calls in the snapshot are possible.
|
||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||
size_t code_range_size =
|
||||
size_t code_range_size_mb =
|
||||
i::kMaximalCodeRangeSize == 0
|
||||
? i::kMaxPCRelativeCodeRangeInMB
|
||||
: std::min(i::kMaximalCodeRangeSize / i::MB,
|
||||
i::kMaxPCRelativeCodeRangeInMB);
|
||||
v8::ResourceConstraints constraints;
|
||||
constraints.set_code_range_size(code_range_size);
|
||||
constraints.set_code_range_size_in_bytes(code_range_size_mb * i::MB);
|
||||
i_isolate->heap()->ConfigureHeap(constraints);
|
||||
// The isolate contains data from builtin compilation that needs
|
||||
// to be written out if builtins are embedded.
|
||||
|
@ -4796,11 +4796,11 @@ HEAP_TEST(Regress538257) {
|
||||
FLAG_manual_evacuation_candidates_selection = true;
|
||||
v8::Isolate::CreateParams create_params;
|
||||
// Set heap limits.
|
||||
create_params.constraints.set_max_semi_space_size_in_kb(1024);
|
||||
create_params.constraints.set_max_young_generation_size_in_bytes(3 * MB);
|
||||
#ifdef DEBUG
|
||||
create_params.constraints.set_max_old_space_size(20);
|
||||
create_params.constraints.set_max_old_generation_size_in_bytes(20 * MB);
|
||||
#else
|
||||
create_params.constraints.set_max_old_space_size(6);
|
||||
create_params.constraints.set_max_old_generation_size_in_bytes(6 * MB);
|
||||
#endif
|
||||
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
|
||||
v8::Isolate* isolate = v8::Isolate::New(create_params);
|
||||
|
@ -982,8 +982,8 @@ TEST(DecideToPretenureDuringCompilation) {
|
||||
// This setting ensures Heap::MaximumSizeScavenge will return `true`.
|
||||
// We need to initialize the heap with at least 1 page, while keeping the
|
||||
// limit low, to ensure the new space fills even on 32-bit architectures.
|
||||
create_params.constraints.set_max_semi_space_size_in_kb(Page::kPageSize /
|
||||
1024);
|
||||
create_params.constraints.set_max_young_generation_size_in_bytes(
|
||||
3 * Page::kPageSize);
|
||||
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
|
||||
v8::Isolate* isolate = v8::Isolate::New(create_params);
|
||||
|
||||
|
@ -4047,7 +4047,7 @@ size_t NearHeapLimitCallback(void* data, size_t current_heap_limit,
|
||||
UNINITIALIZED_TEST(DebugSetOutOfMemoryListener) {
|
||||
v8::Isolate::CreateParams create_params;
|
||||
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
|
||||
create_params.constraints.set_max_old_space_size(10);
|
||||
create_params.constraints.set_max_old_generation_size_in_bytes(10 * i::MB);
|
||||
v8::Isolate* isolate = v8::Isolate::New(create_params);
|
||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||
{
|
||||
|
@ -1522,11 +1522,11 @@ TEST(SliceFromSlice) {
|
||||
UNINITIALIZED_TEST(OneByteArrayJoin) {
|
||||
v8::Isolate::CreateParams create_params;
|
||||
// Set heap limits.
|
||||
create_params.constraints.set_max_semi_space_size_in_kb(1024);
|
||||
create_params.constraints.set_max_young_generation_size_in_bytes(3 * MB);
|
||||
#ifdef DEBUG
|
||||
create_params.constraints.set_max_old_space_size(20);
|
||||
create_params.constraints.set_max_old_generation_size_in_bytes(20 * MB);
|
||||
#else
|
||||
create_params.constraints.set_max_old_space_size(7);
|
||||
create_params.constraints.set_max_old_generation_size_in_bytes(7 * MB);
|
||||
#endif
|
||||
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
|
||||
v8::Isolate* isolate = v8::Isolate::New(create_params);
|
||||
|
@ -50,6 +50,7 @@ v8_source_set("unittests_sources") {
|
||||
"api/interceptor-unittest.cc",
|
||||
"api/isolate-unittest.cc",
|
||||
"api/remote-object-unittest.cc",
|
||||
"api/resource-constraints-unittest.cc",
|
||||
"api/v8-object-unittest.cc",
|
||||
"asmjs/asm-scanner-unittest.cc",
|
||||
"asmjs/asm-types-unittest.cc",
|
||||
|
56
test/unittests/api/resource-constraints-unittest.cc
Normal file
56
test/unittests/api/resource-constraints-unittest.cc
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright 2017 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
#include "include/v8-platform.h"
|
||||
#include "include/v8.h"
|
||||
#include "src/heap/heap.h"
|
||||
|
||||
namespace v8 {
|
||||
|
||||
TEST(ResourceConstraints, ConfigureDefaultsFromHeapSizeSmall) {
|
||||
const size_t KB = static_cast<size_t>(i::KB);
|
||||
const size_t MB = static_cast<size_t>(i::MB);
|
||||
const size_t pm = i::Heap::kPointerMultiplier;
|
||||
v8::ResourceConstraints constraints;
|
||||
constraints.ConfigureDefaultsFromHeapSize(1 * MB, 1 * MB);
|
||||
ASSERT_EQ(i::Heap::MinOldGenerationSize(),
|
||||
constraints.max_old_generation_size_in_bytes());
|
||||
ASSERT_EQ(3 * 512 * pm * KB,
|
||||
constraints.max_young_generation_size_in_bytes());
|
||||
ASSERT_EQ(0u, constraints.initial_old_generation_size_in_bytes());
|
||||
ASSERT_EQ(0u, constraints.initial_young_generation_size_in_bytes());
|
||||
}
|
||||
|
||||
TEST(ResourceConstraints, ConfigureDefaultsFromHeapSizeLarge) {
|
||||
const size_t KB = static_cast<size_t>(i::KB);
|
||||
const size_t MB = static_cast<size_t>(i::MB);
|
||||
const size_t pm = i::Heap::kPointerMultiplier;
|
||||
v8::ResourceConstraints constraints;
|
||||
constraints.ConfigureDefaultsFromHeapSize(100u * MB, 3000u * MB);
|
||||
ASSERT_EQ(3000u * MB - 3 * 8192 * pm * KB,
|
||||
constraints.max_old_generation_size_in_bytes());
|
||||
ASSERT_EQ(3 * 8192 * pm * KB,
|
||||
constraints.max_young_generation_size_in_bytes());
|
||||
ASSERT_EQ(100u * MB - 3 * 512 * pm * KB,
|
||||
constraints.initial_old_generation_size_in_bytes());
|
||||
ASSERT_EQ(3 * 512 * pm * KB,
|
||||
constraints.initial_young_generation_size_in_bytes());
|
||||
}
|
||||
|
||||
TEST(ResourceConstraints, ConfigureDefaults) {
|
||||
const size_t KB = static_cast<size_t>(i::KB);
|
||||
const size_t MB = static_cast<size_t>(i::MB);
|
||||
const size_t pm = i::Heap::kPointerMultiplier;
|
||||
v8::ResourceConstraints constraints;
|
||||
constraints.ConfigureDefaults(2048u * MB, 0u);
|
||||
ASSERT_EQ(512u * pm * MB, constraints.max_old_generation_size_in_bytes());
|
||||
ASSERT_EQ(3 * 4096 * pm * KB,
|
||||
constraints.max_young_generation_size_in_bytes());
|
||||
ASSERT_EQ(0u, constraints.initial_old_generation_size_in_bytes());
|
||||
ASSERT_EQ(0u, constraints.initial_young_generation_size_in_bytes());
|
||||
}
|
||||
|
||||
} // namespace v8
|
@ -19,37 +19,75 @@ namespace internal {
|
||||
using HeapTest = TestWithIsolate;
|
||||
using HeapWithPointerCompressionTest = TestWithIsolateAndPointerCompression;
|
||||
|
||||
TEST(Heap, MaxSpaceSizes) {
|
||||
TEST(Heap, YoungGenerationSizeFromOldGenerationSize) {
|
||||
const size_t MB = static_cast<size_t>(i::MB);
|
||||
const size_t KB = static_cast<size_t>(i::KB);
|
||||
const size_t pm = i::Heap::kPointerMultiplier;
|
||||
size_t old_space, semi_space;
|
||||
ASSERT_EQ(3 * 512u * pm * KB,
|
||||
i::Heap::YoungGenerationSizeFromOldGenerationSize(128u * pm * MB));
|
||||
ASSERT_EQ(3 * 2048u * pm * KB,
|
||||
i::Heap::YoungGenerationSizeFromOldGenerationSize(256u * pm * MB));
|
||||
ASSERT_EQ(3 * 4096u * pm * KB,
|
||||
i::Heap::YoungGenerationSizeFromOldGenerationSize(512u * pm * MB));
|
||||
ASSERT_EQ(3 * 8192u * pm * KB,
|
||||
i::Heap::YoungGenerationSizeFromOldGenerationSize(1024u * pm * MB));
|
||||
}
|
||||
|
||||
i::Heap::ComputeMaxSpaceSizes(0u, &old_space, &semi_space);
|
||||
ASSERT_EQ(128u * pm * MB, old_space);
|
||||
ASSERT_EQ(512u * pm * KB, semi_space);
|
||||
TEST(Heap, GenerationSizesFromHeapSize) {
|
||||
const size_t MB = static_cast<size_t>(i::MB);
|
||||
const size_t KB = static_cast<size_t>(i::KB);
|
||||
const size_t pm = i::Heap::kPointerMultiplier;
|
||||
size_t old, young;
|
||||
|
||||
i::Heap::ComputeMaxSpaceSizes(512u * MB, &old_space, &semi_space);
|
||||
ASSERT_EQ(128u * pm * MB, old_space);
|
||||
ASSERT_EQ(512u * pm * KB, semi_space);
|
||||
i::Heap::GenerationSizesFromHeapSize(1 * KB, &young, &old);
|
||||
ASSERT_EQ(0u, old);
|
||||
ASSERT_EQ(0u, young);
|
||||
|
||||
i::Heap::ComputeMaxSpaceSizes(1024u * MB, &old_space, &semi_space);
|
||||
ASSERT_EQ(256u * pm * MB, old_space);
|
||||
ASSERT_EQ(2048u * pm * KB, semi_space);
|
||||
i::Heap::GenerationSizesFromHeapSize(1 * KB + 3 * 512u * pm * KB, &young,
|
||||
&old);
|
||||
ASSERT_EQ(1 * KB, old);
|
||||
ASSERT_EQ(3 * 512u * pm * KB, young);
|
||||
|
||||
i::Heap::ComputeMaxSpaceSizes(2048u * MB, &old_space, &semi_space);
|
||||
ASSERT_EQ(512u * pm * MB, old_space);
|
||||
ASSERT_EQ(4096u * pm * KB, semi_space);
|
||||
i::Heap::GenerationSizesFromHeapSize(128 * pm * MB + 3 * 512 * pm * KB,
|
||||
&young, &old);
|
||||
ASSERT_EQ(128u * pm * MB, old);
|
||||
ASSERT_EQ(3 * 512u * pm * KB, young);
|
||||
|
||||
i::Heap::ComputeMaxSpaceSizes(static_cast<uint64_t>(4096u) * MB, &old_space,
|
||||
&semi_space);
|
||||
ASSERT_EQ(1024u * pm * MB, old_space);
|
||||
ASSERT_EQ(8192u * pm * KB, semi_space);
|
||||
i::Heap::GenerationSizesFromHeapSize(256u * pm * MB + 3 * 2048 * pm * KB,
|
||||
&young, &old);
|
||||
ASSERT_EQ(256u * pm * MB, old);
|
||||
ASSERT_EQ(3 * 2048u * pm * KB, young);
|
||||
|
||||
i::Heap::ComputeMaxSpaceSizes(static_cast<uint64_t>(8192u) * MB, &old_space,
|
||||
&semi_space);
|
||||
ASSERT_EQ(1024u * pm * MB, old_space);
|
||||
ASSERT_EQ(8192u * pm * KB, semi_space);
|
||||
i::Heap::GenerationSizesFromHeapSize(512u * pm * MB + 3 * 4096 * pm * KB,
|
||||
&young, &old);
|
||||
ASSERT_EQ(512u * pm * MB, old);
|
||||
ASSERT_EQ(3 * 4096u * pm * KB, young);
|
||||
|
||||
i::Heap::GenerationSizesFromHeapSize(1024u * pm * MB + 3 * 8192 * pm * KB,
|
||||
&young, &old);
|
||||
ASSERT_EQ(1024u * pm * MB, old);
|
||||
ASSERT_EQ(3 * 8192u * pm * KB, young);
|
||||
}
|
||||
|
||||
TEST(Heap, HeapSizeFromPhysicalMemory) {
|
||||
const size_t MB = static_cast<size_t>(i::MB);
|
||||
const size_t pm = i::Heap::kPointerMultiplier;
|
||||
|
||||
// The expected value is old_generation_size + 3 * semi_space_size.
|
||||
ASSERT_EQ(128 * pm * MB + 3 * 512 * pm * KB,
|
||||
i::Heap::HeapSizeFromPhysicalMemory(0u));
|
||||
ASSERT_EQ(128 * pm * MB + 3 * 512 * pm * KB,
|
||||
i::Heap::HeapSizeFromPhysicalMemory(512u * MB));
|
||||
ASSERT_EQ(256 * pm * MB + 3 * 2048 * pm * KB,
|
||||
i::Heap::HeapSizeFromPhysicalMemory(1024u * MB));
|
||||
ASSERT_EQ(512 * pm * MB + 3 * 4096 * pm * KB,
|
||||
i::Heap::HeapSizeFromPhysicalMemory(2048u * MB));
|
||||
ASSERT_EQ(
|
||||
1024 * pm * MB + 3 * 8192 * pm * KB,
|
||||
i::Heap::HeapSizeFromPhysicalMemory(static_cast<uint64_t>(4096u) * MB));
|
||||
ASSERT_EQ(
|
||||
1024 * pm * MB + 3 * 8192 * pm * KB,
|
||||
i::Heap::HeapSizeFromPhysicalMemory(static_cast<uint64_t>(8192u) * MB));
|
||||
}
|
||||
|
||||
TEST_F(HeapTest, ASLR) {
|
||||
|
Loading…
Reference in New Issue
Block a user