8372150: Parallel: Tighten requirements around heap sizes with NUMA and Large Pages

Reviewed-by: ayang, stefank, aboldtch, stuefe
This commit is contained in:
Joel Sikström 2025-11-27 09:38:59 +00:00
parent 1f417e7761
commit 4ac3395634
11 changed files with 118 additions and 105 deletions

View File

@ -37,8 +37,45 @@
#include "utilities/defaultStream.hpp"
#include "utilities/powerOfTwo.hpp"
size_t ParallelArguments::conservative_max_heap_alignment() {
return compute_heap_alignment();
static size_t num_young_spaces() {
// When using NUMA, we create one MutableNUMASpace for each NUMA node
const size_t num_eden_spaces = UseNUMA ? os::numa_get_groups_num() : 1;
// The young generation must have room for eden + two survivors
return num_eden_spaces + 2;
}
static size_t num_old_spaces() {
return 1;
}
void ParallelArguments::initialize_alignments() {
// Initialize card size before initializing alignments
CardTable::initialize_card_size();
const size_t card_table_alignment = CardTable::ct_max_alignment_constraint();
SpaceAlignment = ParallelScavengeHeap::default_space_alignment();
if (UseLargePages) {
const size_t total_spaces = num_young_spaces() + num_old_spaces();
const size_t page_size = os::page_size_for_region_unaligned(MaxHeapSize, total_spaces);
ParallelScavengeHeap::set_desired_page_size(page_size);
if (page_size == os::vm_page_size()) {
log_warning(gc, heap)("MaxHeapSize (%zu) must be large enough for %zu * page-size; Disabling UseLargePages for heap",
MaxHeapSize, total_spaces);
}
if (page_size > SpaceAlignment) {
SpaceAlignment = page_size;
}
HeapAlignment = lcm(page_size, card_table_alignment);
} else {
assert(is_aligned(SpaceAlignment, os::vm_page_size()), "");
ParallelScavengeHeap::set_desired_page_size(os::vm_page_size());
HeapAlignment = card_table_alignment;
}
}
void ParallelArguments::initialize() {
@ -98,49 +135,36 @@ void ParallelArguments::initialize() {
FullGCForwarding::initialize_flags(heap_reserved_size_bytes());
}
void ParallelArguments::initialize_alignments() {
// Initialize card size before initializing alignments
CardTable::initialize_card_size();
SpaceAlignment = ParallelScavengeHeap::default_space_alignment();
HeapAlignment = compute_heap_alignment();
}
size_t ParallelArguments::conservative_max_heap_alignment() {
// The card marking array and the offset arrays for old generations are
// committed in os pages as well. Make sure they are entirely full (to
// avoid partial page problems), e.g. if 512 bytes heap corresponds to 1
// byte entry and the os page size is 4096, the maximum heap size should
// be 512*4096 = 2MB aligned.
void ParallelArguments::initialize_heap_flags_and_sizes_one_pass() {
// Do basic sizing work
GenArguments::initialize_heap_flags_and_sizes();
}
size_t alignment = CardTable::ct_max_alignment_constraint();
void ParallelArguments::initialize_heap_flags_and_sizes() {
initialize_heap_flags_and_sizes_one_pass();
if (!UseLargePages) {
ParallelScavengeHeap::set_desired_page_size(os::vm_page_size());
return;
if (UseLargePages) {
// In presence of large pages we have to make sure that our
// alignment is large page aware.
alignment = lcm(os::large_page_size(), alignment);
}
// If using large-page, need to update SpaceAlignment so that spaces are page-size aligned.
const size_t min_pages = 4; // 1 for eden + 1 for each survivor + 1 for old
const size_t page_sz = os::page_size_for_region_aligned(MinHeapSize, min_pages);
ParallelScavengeHeap::set_desired_page_size(page_sz);
if (page_sz == os::vm_page_size()) {
log_warning(gc, heap)("MinHeapSize (%zu) must be large enough for 4 * page-size; Disabling UseLargePages for heap", MinHeapSize);
return;
}
// Space is largepage-aligned.
size_t new_alignment = page_sz;
if (new_alignment != SpaceAlignment) {
SpaceAlignment = new_alignment;
// Redo everything from the start
initialize_heap_flags_and_sizes_one_pass();
}
}
size_t ParallelArguments::heap_reserved_size_bytes() {
return MaxHeapSize;
return alignment;
}
CollectedHeap* ParallelArguments::create_heap() {
return new ParallelScavengeHeap();
}
size_t ParallelArguments::young_gen_size_lower_bound() {
return num_young_spaces() * SpaceAlignment;
}
size_t ParallelArguments::old_gen_size_lower_bound() {
return num_old_spaces() * SpaceAlignment;
}
size_t ParallelArguments::heap_reserved_size_bytes() {
return MaxHeapSize;
}

View File

@ -1,5 +1,6 @@
/*
* Copyright (c) 2017, Red Hat, Inc. and/or its affiliates.
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,21 +26,16 @@
#ifndef SHARE_GC_PARALLEL_PARALLELARGUMENTS_HPP
#define SHARE_GC_PARALLEL_PARALLELARGUMENTS_HPP
#include "gc/shared/gcArguments.hpp"
#include "gc/shared/genArguments.hpp"
class CollectedHeap;
class ParallelArguments : public GenArguments {
private:
virtual void initialize_alignments();
virtual void initialize_heap_flags_and_sizes();
void initialize_heap_flags_and_sizes_one_pass();
virtual void initialize();
virtual size_t conservative_max_heap_alignment();
virtual CollectedHeap* create_heap();
virtual size_t young_gen_size_lower_bound();
virtual size_t old_gen_size_lower_bound();
public:
static size_t heap_reserved_size_bytes();

View File

@ -1,5 +1,6 @@
/*
* Copyright (c) 2017, Red Hat, Inc. and/or its affiliates.
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -27,11 +28,49 @@
#include "gc/shared/fullGCForwarding.hpp"
#include "gc/shared/gcArguments.hpp"
static size_t compute_heap_alignment() {
// The card marking array and the offset arrays for old generations are
// committed in os pages as well. Make sure they are entirely full (to
// avoid partial page problems), e.g. if 512 bytes heap corresponds to 1
// byte entry and the os page size is 4096, the maximum heap size should
// be 512*4096 = 2MB aligned.
size_t alignment = CardTable::ct_max_alignment_constraint();
if (UseLargePages) {
// In presence of large pages we have to make sure that our
// alignment is large page aware.
alignment = lcm(os::large_page_size(), alignment);
}
return alignment;
}
void SerialArguments::initialize_alignments() {
// Initialize card size before initializing alignments
CardTable::initialize_card_size();
SpaceAlignment = (size_t)Generation::GenGrain;
HeapAlignment = compute_heap_alignment();
}
void SerialArguments::initialize() {
GCArguments::initialize();
FullGCForwarding::initialize_flags(MaxHeapSize);
}
size_t SerialArguments::conservative_max_heap_alignment() {
return MAX2((size_t)Generation::GenGrain, compute_heap_alignment());
}
CollectedHeap* SerialArguments::create_heap() {
return new SerialHeap();
}
size_t SerialArguments::young_gen_size_lower_bound() {
// The young generation must be aligned and have room for eden + two survivors
return 3 * SpaceAlignment;
}
size_t SerialArguments::old_gen_size_lower_bound() {
return SpaceAlignment;
}

View File

@ -1,5 +1,6 @@
/*
* Copyright (c) 2017, Red Hat, Inc. and/or its affiliates.
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -27,12 +28,14 @@
#include "gc/shared/genArguments.hpp"
class CollectedHeap;
class SerialArguments : public GenArguments {
private:
virtual void initialize_alignments();
virtual void initialize();
virtual size_t conservative_max_heap_alignment();
virtual CollectedHeap* create_heap();
virtual size_t young_gen_size_lower_bound();
virtual size_t old_gen_size_lower_bound();
};
#endif // SHARE_GC_SERIAL_SERIALARGUMENTS_HPP

View File

@ -62,24 +62,6 @@ void GCArguments::initialize_heap_sizes() {
initialize_size_info();
}
size_t GCArguments::compute_heap_alignment() {
// The card marking array and the offset arrays for old generations are
// committed in os pages as well. Make sure they are entirely full (to
// avoid partial page problems), e.g. if 512 bytes heap corresponds to 1
// byte entry and the os page size is 4096, the maximum heap size should
// be 512*4096 = 2MB aligned.
size_t alignment = CardTable::ct_max_alignment_constraint();
if (UseLargePages) {
// In presence of large pages we have to make sure that our
// alignment is large page aware.
alignment = lcm(os::large_page_size(), alignment);
}
return alignment;
}
#ifdef ASSERT
void GCArguments::assert_flags() {
assert(InitialHeapSize <= MaxHeapSize, "Ergonomics decided on incompatible initial and maximum heap sizes");

View File

@ -45,6 +45,8 @@ protected:
public:
virtual void initialize();
// Return the (conservative) maximum heap alignment
virtual size_t conservative_max_heap_alignment() = 0;
// Used by heap size heuristics to determine max
@ -59,8 +61,6 @@ public:
}
void initialize_heap_sizes();
static size_t compute_heap_alignment();
};
#endif // SHARE_GC_SHARED_GCARGUMENTS_HPP

View File

@ -42,17 +42,6 @@ size_t MaxOldSize = 0;
// See more in JDK-8346005
size_t OldSize = ScaleForWordSize(4*M);
size_t GenArguments::conservative_max_heap_alignment() { return (size_t)Generation::GenGrain; }
static size_t young_gen_size_lower_bound() {
// The young generation must be aligned and have room for eden + two survivors
return 3 * SpaceAlignment;
}
static size_t old_gen_size_lower_bound() {
return SpaceAlignment;
}
size_t GenArguments::scale_by_NewRatio_aligned(size_t base_size, size_t alignment) {
return align_down_bounded(base_size / (NewRatio + 1), alignment);
}
@ -64,13 +53,6 @@ static size_t bound_minus_alignment(size_t desired_size,
return MIN2(desired_size, max_minus);
}
void GenArguments::initialize_alignments() {
// Initialize card size before initializing alignments
CardTable::initialize_card_size();
SpaceAlignment = (size_t)Generation::GenGrain;
HeapAlignment = compute_heap_alignment();
}
void GenArguments::initialize_heap_flags_and_sizes() {
GCArguments::initialize_heap_flags_and_sizes();

View File

@ -38,17 +38,16 @@ extern size_t OldSize;
class GenArguments : public GCArguments {
friend class TestGenCollectorPolicy; // Testing
private:
virtual void initialize_alignments();
virtual void initialize_size_info();
// Return the (conservative) maximum heap alignment
virtual size_t conservative_max_heap_alignment();
DEBUG_ONLY(void assert_flags();)
DEBUG_ONLY(void assert_size_info();)
static size_t scale_by_NewRatio_aligned(size_t base_size, size_t alignment);
virtual size_t young_gen_size_lower_bound() = 0;
virtual size_t old_gen_size_lower_bound() = 0;
protected:
virtual void initialize_heap_flags_and_sizes();
};

View File

@ -250,7 +250,7 @@ static JVMFlag::Error MaxSizeForHeapAlignment(const char* name, size_t value, bo
} else
#endif
{
heap_alignment = GCArguments::compute_heap_alignment();
heap_alignment = Arguments::conservative_max_heap_alignment();
}
return MaxSizeForAlignment(name, value, heap_alignment, verbose);

View File

@ -1478,10 +1478,9 @@ void Arguments::set_conservative_max_heap_alignment() {
// the alignments imposed by several sources: any requirements from the heap
// itself and the maximum page size we may run the VM with.
size_t heap_alignment = GCConfig::arguments()->conservative_max_heap_alignment();
_conservative_max_heap_alignment = MAX4(heap_alignment,
_conservative_max_heap_alignment = MAX3(heap_alignment,
os::vm_allocation_granularity(),
os::max_page_size(),
GCArguments::compute_heap_alignment());
os::max_page_size());
assert(is_power_of_2(_conservative_max_heap_alignment), "Expected to be a power-of-2");
}

View File

@ -140,17 +140,6 @@ class TestGenCollectorPolicy {
ASSERT_EQ(param, NewSize);
}
};
class SetMaxNewSizeCmd : public BinaryExecutor {
public:
SetMaxNewSizeCmd(size_t param1, size_t param2) : BinaryExecutor(param1, param2) { }
void execute() {
size_t heap_alignment = GCArguments::compute_heap_alignment();
size_t new_size_value = align_up(MaxHeapSize, heap_alignment)
- param1 + param2;
FLAG_SET_CMDLINE(MaxNewSize, new_size_value);
}
};
};