The actual heap size may differ from what the user specified in the command line due to alignment and ergonomics adjustments. By default, the heap is 2MB aligned, you can check the source code from OpenJDK to see how this is implemented.
size_t CollectorPolicy::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. // There is only the GenRemSet in Hotspot and only the GenRemSet::CardTable // is supported. // Requirements of any new remembered set implementations must be added here. size_t alignment = GenRemSet::max_alignment_constraint(GenRemSet::CardTable); // 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; }
1044381696 from -XX:+PrintFlagsFinal is the final heap size after 2MB-alignment of 1043086336 from -XX:+PrintCommandLineFlags . Since 1043086336 is not 2M-aligned, i.e. X / (2*1024*1024) = 497.38 - fractional. The nearest multiple of 2M to it is 1044381696: X / (2*1024*1024) = 498