Skip to content

Instantly share code, notes, and snippets.

@rednaxelafx
Created November 18, 2011 06:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rednaxelafx/1375782 to your computer and use it in GitHub Desktop.
Save rednaxelafx/1375782 to your computer and use it in GitHub Desktop.
HotSpot's max heap size rounds up to some alignment
$ getconf PAGESIZE
4096
diff -r f0f676c5a2c6 src/share/vm/gc_implementation/parallelScavenge/generationSizer.hpp
--- a/src/share/vm/gc_implementation/parallelScavenge/generationSizer.hpp Tue Mar 15 19:30:16 2011 -0700
+++ b/src/share/vm/gc_implementation/parallelScavenge/generationSizer.hpp Fri Nov 18 14:46:18 2011 +0800
@@ -34,7 +34,9 @@
public:
GenerationSizer() {
// Partial init only!
+tty->print_cr("GenerationSizer(), before initialize_flags(),MaxHeapSize=%d", MaxHeapSize);
initialize_flags();
+tty->print_cr("GenerationSizer(), after initialize_flags(), MaxHeapSize=%d", MaxHeapSize);
initialize_size_info();
}
diff -r f0f676c5a2c6 src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp
--- a/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp Tue Mar 15 19:30:16 2011 -0700
+++ b/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp Fri Nov 18 14:46:18 2011 +0800
@@ -69,11 +69,11 @@
jint ParallelScavengeHeap::initialize() {
CollectedHeap::pre_initialize();
-
+tty->print_cr("ParallelScavengeHeap::initialize(), before new GenerationSizer(), MaxHeapSize=%d", MaxHeapSize);
// Cannot be initialized until after the flags are parsed
// GenerationSizer flag_parser;
_collector_policy = new GenerationSizer();
-
+tty->print_cr("ParallelScavengeHeap::initialize(), after new GenerationSizer(), MaxHeapSize=%d", MaxHeapSize);
size_t yg_min_size = _collector_policy->min_young_gen_size();
size_t yg_max_size = _collector_policy->max_young_gen_size();
size_t og_min_size = _collector_policy->min_old_gen_size();
diff -r f0f676c5a2c6 src/share/vm/memory/collectorPolicy.cpp
--- a/src/share/vm/memory/collectorPolicy.cpp Tue Mar 15 19:30:16 2011 -0700
+++ b/src/share/vm/memory/collectorPolicy.cpp Fri Nov 18 14:46:18 2011 +0800
@@ -256,14 +256,17 @@
}
void TwoGenerationCollectorPolicy::initialize_flags() {
+tty->print_cr("NewSize=%d, OldSize=%d, MaxHeapSize=%d", NewSize, OldSize, MaxHeapSize);
GenCollectorPolicy::initialize_flags();
-
+tty->print_cr("NewSize=%d, OldSize=%d, MaxHeapSize=%d", NewSize, OldSize, MaxHeapSize);
OldSize = align_size_down(OldSize, min_alignment());
+tty->print_cr("NewSize=%d, OldSize=%d, MaxHeapSize=%d", NewSize, OldSize, MaxHeapSize);
if (NewSize + OldSize > MaxHeapSize) {
MaxHeapSize = NewSize + OldSize;
}
+tty->print_cr("MaxHeapSize=%d", MaxHeapSize);
MaxHeapSize = align_size_up(MaxHeapSize, max_alignment());
-
+tty->print_cr("MaxHeapSize=%d", MaxHeapSize);
always_do_update_barrier = UseConcMarkSweepGC;
BlockOffsetArrayUseUnallocatedBlock =
BlockOffsetArrayUseUnallocatedBlock || ParallelGCThreads > 0;
diff -r f0f676c5a2c6 src/share/vm/memory/universe.cpp
--- a/src/share/vm/memory/universe.cpp Tue Mar 15 19:30:16 2011 -0700
+++ b/src/share/vm/memory/universe.cpp Fri Nov 18 14:46:18 2011 +0800
@@ -777,12 +777,12 @@
"archive file not closed or shared spaces not disabled.");
}
}
-
+tty->print_cr("universe_init(), before Universe::initialize_heap(), MaxHeapSize=%d", MaxHeapSize);
jint status = Universe::initialize_heap();
if (status != JNI_OK) {
return status;
}
-
+tty->print_cr("universe_init(), after Universe::initialize_heap(), MaxHeapSize=%d", MaxHeapSize);
// We have a heap so create the methodOop caches before
// CompactingPermGenGen::initialize_oops() tries to populate them.
Universe::_finalizer_register_cache = new LatestMethodOopCache();
@@ -920,12 +920,12 @@
Universe::_collectedHeap = new GenCollectedHeap(gc_policy);
}
-
+tty->print_cr("Universe::initialize_heap(), before Universe::heap()->initialize(), MaxHeapSize=%d", MaxHeapSize);
jint status = Universe::heap()->initialize();
if (status != JNI_OK) {
return status;
}
-
+tty->print_cr("Universe::initialize_heap(), after Universe::heap()->initialize(), MaxHeapSize=%d", MaxHeapSize);
#ifdef _LP64
if (UseCompressedOops) {
// Subtract a page because something can get allocated at heap base.
diff -r f0f676c5a2c6 src/share/vm/runtime/init.cpp
--- a/src/share/vm/runtime/init.cpp Tue Mar 15 19:30:16 2011 -0700
+++ b/src/share/vm/runtime/init.cpp Fri Nov 18 14:46:18 2011 +0800
@@ -95,10 +95,11 @@
codeCache_init();
VM_Version_init();
stubRoutines_init1();
+tty->print_cr("init_globals(), before universe_init(), MaxHeapSize=%d", MaxHeapSize);
jint status = universe_init(); // dependent on codeCache_init and stubRoutines_init
if (status != JNI_OK)
return status;
-
+tty->print_cr("init_globals(), after universe_init(), MaxHeapSize=%d", MaxHeapSize);
interpreter_init(); // before any methods loaded
invocationCounter_init(); // before any methods loaded
marksweep_init();
diff -r f0f676c5a2c6 src/share/vm/runtime/thread.cpp
--- a/src/share/vm/runtime/thread.cpp Tue Mar 15 19:30:16 2011 -0700
+++ b/src/share/vm/runtime/thread.cpp Fri Nov 18 14:46:18 2011 +0800
@@ -3017,7 +3017,7 @@
// Parse arguments
jint parse_result = Arguments::parse(args);
if (parse_result != JNI_OK) return parse_result;
-
+tty->print_cr("Thread::create_vm(), after Arguments::parse(), MaxHeapSize=%d", MaxHeapSize);
if (PauseAtStartup) {
os::pause();
}
@@ -3056,9 +3056,10 @@
// Initialize TLS
ThreadLocalStorage::init();
-
+tty->print_cr("Thread::create_vm(), before vm_init_globals(), MaxHeapSize=%d", MaxHeapSize);
// Initialize global data structures and create system classes in heap
vm_init_globals();
+tty->print_cr("Thread::create_vm(), after vm_init_globals(), MaxHeapSize=%d", MaxHeapSize);
// Attach the main thread to this os thread
JavaThread* main_thread = new JavaThread();
@@ -3087,7 +3088,7 @@
// Initialize Java-Level synchronization subsystem
ObjectMonitor::Initialize() ;
-
+tty->print_cr("Thread::create_vm(), before init_globals(), MaxHeapSize=%d", MaxHeapSize);
// Initialize global modules
jint status = init_globals();
if (status != JNI_OK) {
@@ -3095,7 +3096,7 @@
*canTryAgain = false; // don't let caller call JNI_CreateJavaVM again
return status;
}
-
+tty->print_cr("Thread::create_vm(), after init_globals(), MaxHeapSize=%d", MaxHeapSize);
// Should be done after the heap is fully created
main_thread->cache_global_variables();

ParallelScavenge's heap size settings are initialized in class GenerationSizer : public TwoGenerationCollectorPolicy. And it goes all the way up, to CollectorPolicy::initialize_size_info(), where it does a set_max_heap_byte_size(align_size_up(MaxHeapSize, max_alignment()));.

size_t GenCollectorPolicy::compute_max_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 = GenRemSet::max_alignment_constraint(rem_set_name());

  // Parallel GC does its own alignment of the generations to avoid requiring a
  // large page (256M on some platforms) for the permanent generation.  The
  // other collectors should also be updated to do their own alignment and then
  // this use of lcm() should be removed.
  if (UseLargePages && !UseParallelGC) {
      // 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;
}

uintx GenRemSet::max_alignment_constraint(Name nm) {
  switch (nm) {
  case GenRemSet::CardTable:
    return CardTableRS::ct_max_alignment_constraint();
  default:
    guarantee(false, "Unrecognized GenRemSet type.");
    return (0); // Make Windows compiler happy
  }
}

  static uintx ct_max_alignment_constraint() {
    return CardTableModRefBS::ct_max_alignment_constraint();
  }

uintx CardTableModRefBS::ct_max_alignment_constraint() {
  return card_size * os::vm_page_size();
}

  enum SomePublicConstants {
    card_shift                  = 9,
    card_size                   = 1 << card_shift,
    card_size_in_words          = card_size / sizeof(HeapWord)
  };

// on Linux
int os::vm_page_size() {
  // Seems redundant as all get out
  assert(os::Linux::page_size() != -1, "must call os::init");
  return os::Linux::page_size();
}

void os::init(void) {
  // ...
  Linux::set_page_size(sysconf(_SC_PAGESIZE));
  if (Linux::page_size() == -1) {
    fatal(err_msg("os_linux.cpp: os::init: sysconf failed (%s)",
                  strerror(errno)));
  }
  init_page_sizes((size_t) Linux::page_size());
  // ...
}

So the max heap size in my environment is 2MB aligned.

$ java -Xms2m -Xmx2m -XX:PermSize=1m -XX:+PrintCommandLineFlags
-XX:InitialHeapSize=2097152 -XX:MaxHeapSize=2097152 -XX:ParallelGCThreads=4 -XX:PermSize=1048576 -XX:+PrintCommandLineFlags -XX:+UseCompressedOops -XX:+UseParallelGC 

$ java -Xms2m -Xmx2m -XX:PermSize=1m -XX:+PrintGCDetails gives:

Heap
 PSYoungGen      total 2368K, used 188K [0x00000000ffd60000, 0x0000000100000000, 0x0000000100000000)
  eden space 2048K, 9% used [0x00000000ffd60000,0x00000000ffd8f078,0x00000000fff60000)
  from space 320K, 0% used [0x00000000fffb0000,0x00000000fffb0000,0x0000000100000000)
  to   space 320K, 0% used [0x00000000fff60000,0x00000000fff60000,0x00000000fffb0000)
 PSOldGen        total 768K, used 0K [0x00000000ff800000, 0x00000000ff8c0000, 0x00000000ffd60000)
  object space 768K, 0% used [0x00000000ff800000,0x00000000ff800000,0x00000000ff8c0000)
 PSPermGen       total 2368K, used 2316K [0x00000000fa600000, 0x00000000fa850000, 0x00000000ff800000)
  object space 2368K, 97% used [0x00000000fa600000,0x00000000fa843290,0x00000000fa850000)

The heap layout is:

0x00000000fa600000 <- PSPermGen -> 0x00000000ff800000 <- PSOldGen -> 0x00000000ffd60000 <- PSYoungGen -> 0x0000000100000000

That's 8MB of Java heap (young: 2.625MB, old: 5.375MB), even though -Xmx is 2m; and 82m of PermGen, totaling 90MB of GC heap. What?

$ java -version
java version "1.6.0_25-ea-fastdebug"
Java(TM) SE Runtime Environment (build 1.6.0_25-ea-fastdebug-b03)
Java HotSpot(TM) 64-Bit Server VM (build 20.0-b10-fastdebug, mixed mode)
$ java -Xmx2m -Xms2m -XX:PermSize=1m -XX:+TracePageSizes -XX:+PrintCommandLineFlags -XX:+PrintGCDetails
VM option 'PermSize=1m'
VM option '+TracePageSizes'
VM option '+PrintCommandLineFlags'
VM option '+PrintGCDetails'
-XX:InitialHeapSize=2097152 -XX:MaxHeapSize=2097152 -XX:ParallelGCThreads=4 -XX:PermSize=1048576 -XX:+PrintCommandLineFlags -XX:+PrintGCDetails -XX:+TracePageSizes -XX:+UseCompressedOops -XX:+UseParallelGC 
code heap:  min=2555904 max=50331648 pg_sz=4096 base=0x00002aaaab026000 size=50331648
ps heap raw:  1024,83968 768,5504 1280,2688 92160
ps heap rnd:  1024,83968 768,5504 1280,2688 92160
ps perm:  min=1048576 max=85983232 pg_sz=4096 base=0x00000000fa600000 size=85983232
ps main:  min=2097152 max=8388608 pg_sz=4096 base=0x00000000ff800000 size=8388608
card table:  min=184321 max=184321 pg_sz=4096 base=0x00002aaaae0e6000 size=188416

Heap
 PSYoungGen      total 2368K, used 188K [0x00000000ffd60000, 0x0000000100000000, 0x0000000100000000)
  eden space 2048K, 9% used [0x00000000ffd60000,0x00000000ffd8f0d0,0x00000000fff60000)
  from space 320K, 0% used [0x00000000fffb0000,0x00000000fffb0000,0x0000000100000000)
  to   space 320K, 0% used [0x00000000fff60000,0x00000000fff60000,0x00000000fffb0000)
 PSOldGen        total 768K, used 0K [0x00000000ff800000, 0x00000000ff8c0000, 0x00000000ffd60000)
  object space 768K, 0% used [0x00000000ff800000,0x00000000ff800000,0x00000000ff8c0000)
 PSPermGen       total 2560K, used 2525K [0x00000000fa600000, 0x00000000fa880000, 0x00000000ff800000)
  object space 2560K, 98% used [0x00000000fa600000,0x00000000fa8777a8,0x00000000fa880000)
static void trace_gen_sizes(const char* const str,
                            size_t pg_min, size_t pg_max,
                            size_t og_min, size_t og_max,
                            size_t yg_min, size_t yg_max)
{
  if (TracePageSizes) {
    tty->print_cr("%s:  " SIZE_FORMAT "," SIZE_FORMAT " "
                  SIZE_FORMAT "," SIZE_FORMAT " "
                  SIZE_FORMAT "," SIZE_FORMAT " "
                  SIZE_FORMAT,
                  str, pg_min / K, pg_max / K,
                  og_min / K, og_max / K,
                  yg_min / K, yg_max / K,
                  (pg_max + og_max + yg_max) / K);
  }
}
$ java -Xmx2m -Xms2m -XX:PermSize=1m -XX:+PrintCommandLineFlags -XX:+PrintFlagsFinal | grep MaxHeapSize
-XX:InitialHeapSize=2097152 -XX:MaxHeapSize=2097152 -XX:ParallelGCThreads=4 -XX:PermSize=1048576 -XX:+PrintCommandLineFlags -XX:+PrintFlagsFinal -XX:+UseCompressedOops -XX:+UseParallelGC 
    uintx MaxHeapSize                              := 8388608         {product}           
$ java -version
java version "1.6.0_29"
Java(TM) SE Runtime Environment (build 1.6.0_29-b11)
Java HotSpot(TM) 64-Bit Server VM (build 20.4-b02, mixed mode)
void TwoGenerationCollectorPolicy::initialize_flags() {
  GenCollectorPolicy::initialize_flags();

  OldSize = align_size_down(OldSize, min_alignment());
  if (NewSize + OldSize > MaxHeapSize) {
    MaxHeapSize = NewSize + OldSize;
  }
  MaxHeapSize = align_size_up(MaxHeapSize, max_alignment());
//...
}

If -Xmx/MaxHeapSize is smaller than the default NewSize + OldSize, then MaxHeapSize will be expanded.

$ $JAVA_HOME/bin/java -Xmx2m -Xms2m -XX:PermSize=1m -XX:+PrintCommandLineFlags -XX:+PrintGCDetails
-XX:InitialHeapSize=2097152 -XX:MaxHeapSize=2097152 -XX:ParallelGCThreads=13 -XX:PermSize=1048576 -XX:+PrintCommandLineFlags -XX:+PrintGCDetails -XX:+UseCompressedOops -XX:+UseParallelGC 
Thread::create_vm(), after Arguments::parse(), MaxHeapSize=2097152
Thread::create_vm(), before vm_init_globals(), MaxHeapSize=2097152
Thread::create_vm(), after vm_init_globals(), MaxHeapSize=2097152
Thread::create_vm(), before init_globals(), MaxHeapSize=2097152
init_globals(), before universe_init(), MaxHeapSize=2097152
universe_init(), before Universe::initialize_heap(), MaxHeapSize=2097152
Universe::initialize_heap(), before Universe::heap()->initialize(), MaxHeapSize=2097152
ParallelScavengeHeap::initialize(), before new GenerationSizer(), MaxHeapSize=2097152
GenerationSizer(), before initialize_flags(),MaxHeapSize=2097152
NewSize=1363144, OldSize=5452592, MaxHeapSize=2097152
NewSize=1310720, OldSize=5452592, MaxHeapSize=2097152
NewSize=1310720, OldSize=5439488, MaxHeapSize=2097152
MaxHeapSize=6750208
MaxHeapSize=8388608
GenerationSizer(), after initialize_flags(), MaxHeapSize=8388608
ParallelScavengeHeap::initialize(), after new GenerationSizer(), MaxHeapSize=8388608
Universe::initialize_heap(), after Universe::heap()->initialize(), MaxHeapSize=8388608
universe_init(), after Universe::initialize_heap(), MaxHeapSize=8388608
init_globals(), after universe_init(), MaxHeapSize=8388608
Thread::create_vm(), after init_globals(), MaxHeapSize=8388608

Heap
 PSYoungGen      total 2368K, used 188K [0x00000000ffd60000, 0x0000000100000000, 0x0000000100000000)
  eden space 2048K, 9% used [0x00000000ffd60000,0x00000000ffd8f118,0x00000000fff60000)
  from space 320K, 0% used [0x00000000fffb0000,0x00000000fffb0000,0x0000000100000000)
  to   space 320K, 0% used [0x00000000fff60000,0x00000000fff60000,0x00000000fffb0000)
 PSOldGen        total 768K, used 0K [0x00000000ff800000, 0x00000000ff8c0000, 0x00000000ffd60000)
  object space 768K, 0% used [0x00000000ff800000,0x00000000ff800000,0x00000000ff8c0000)
 PSPermGen       total 2368K, used 2243K [0x00000000fa600000, 0x00000000fa850000, 0x00000000ff800000)
  object space 2368K, 94% used [0x00000000fa600000,0x00000000fa830d40,0x00000000fa850000)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment