I have been doing some startup time research for Leyden and different GCs, and noticed that G1 startup time varies wildly depending on the heap size requested.
Look:
$ cat Hello.java
public class Hello {
public static void main(String... args) throws Throwable {
System.out.println("Hello world!");
}
}
$ javac Hello.java
$ hyperfine -w 10 -r 10 "build/linux-x86_64-server-release/images/jdk/bin/java -XX:+UseG1GC -Xmx128m Hello"
Benchmark 1: build/linux-x86_64-server-release/images/jdk/bin/java -XX:+UseG1GC -Xmx128m Hello
Time (mean ± σ): 22.5 ms ± 0.5 ms [User: 13.6 ms, System: 17.3 ms]
Range (min ... max): 22.1 ms ... 23.7 ms 10 runs
$ hyperfine -w 10 -r 10 "build/linux-x86_64-server-release/images/jdk/bin/java -XX:+UseG1GC -Xmx2g Hello"
Benchmark 1: build/linux-x86_64-server-release/images/jdk/bin/java -XX:+UseG1GC -Xmx2g Hello
Time (mean ± σ): 43.8 ms ± 2.3 ms [User: 16.4 ms, System: 35.5 ms]
Range (min ... max): 41.7 ms ... 48.3 ms 10 runs
Profiling shows the hot path is in heap region commits.
- 44.45% Threads::create_vm(JavaVMInitArgs*, bool*)
- 32.03% init_globals()
- 31.10% universe_init()
- 26.44% G1CollectedHeap::initialize()
- 25.84% G1CollectedHeap::expand(unsigned long, WorkerThreads*, double*)
- G1HeapRegionManager::expand_by(unsigned int, WorkerThreads*)
- 20.38% G1HeapRegionManager::expand(unsigned int, unsigned int, WorkerThreads
- 9.70% G1HeapRegionManager::commit_regions(unsigned int, unsigned long, Wo
- 8.07% G1RegionsSmallerThanCommitSizeMapper::commit_regions(unsigned in
- 7.99% G1PageBasedVirtualSpace::commit(unsigned long, unsigned long)
+ 7.92% os::commit_memory_or_exit(char*, unsigned long, unsigned l
+ 1.53% G1FromCardCache::invalidate(unsigned int, unsigned long)
- 8.73% G1RegionsSmallerThanCommitSizeMapper::commit_regions(unsigned int,
- G1PageBasedVirtualSpace::commit(unsigned long, unsigned long)
+ 8.55% os::commit_memory_or_exit(char*, unsigned long, unsigned long
- 1.83% G1CollectedHeap::new_heap_region(unsigned int, MemRegion)
- G1HeapRegion::G1HeapRegion(unsigned int, G1BlockOffsetTable*, MemRegio
- 1.37% G1HeapRegionRemSet::G1HeapRegionRemSet(G1HeapRegion*, G1CardS
0.70% G1CardSetMemoryManager::G1CardSetMemoryManager(G1CardSetCo
+ 4.81% __memset_avx2_unaligned_erms
+ 0.65% G1HeapRegionManager::initialize_regions(unsigned int, unsigned int)
+ 3.35% Metaspace::global_initialize()
0.60% MetaspaceShared::initialize_shared_spaces()
Reducing -Xms helps:
$ hyperfine -w 10 -r 10 "build/linux-x86_64-server-release/images/jdk/bin/java -XX:+UseG1GC -Xms128m -Xmx2g Hello"
Benchmark 1: build/linux-x86_64-server-release/images/jdk/bin/java -XX:+UseG1GC -Xms128m -Xmx2g Hello
Time (mean ± σ): 23.4 ms ± 0.4 ms [User: 12.6 ms, System: 18.5 ms]
Range (min … max): 22.9 ms … 24.1 ms 10 runs
While we should really consider to trim the default initial heap size (JDK-8348278), it would not help if user specifies Xms. So, it would be great to see if we can improve this code path across large initial heap sizes.
Look:
$ cat Hello.java
public class Hello {
public static void main(String... args) throws Throwable {
System.out.println("Hello world!");
}
}
$ javac Hello.java
$ hyperfine -w 10 -r 10 "build/linux-x86_64-server-release/images/jdk/bin/java -XX:+UseG1GC -Xmx128m Hello"
Benchmark 1: build/linux-x86_64-server-release/images/jdk/bin/java -XX:+UseG1GC -Xmx128m Hello
Time (mean ± σ): 22.5 ms ± 0.5 ms [User: 13.6 ms, System: 17.3 ms]
Range (min ... max): 22.1 ms ... 23.7 ms 10 runs
$ hyperfine -w 10 -r 10 "build/linux-x86_64-server-release/images/jdk/bin/java -XX:+UseG1GC -Xmx2g Hello"
Benchmark 1: build/linux-x86_64-server-release/images/jdk/bin/java -XX:+UseG1GC -Xmx2g Hello
Time (mean ± σ): 43.8 ms ± 2.3 ms [User: 16.4 ms, System: 35.5 ms]
Range (min ... max): 41.7 ms ... 48.3 ms 10 runs
Profiling shows the hot path is in heap region commits.
- 44.45% Threads::create_vm(JavaVMInitArgs*, bool*)
- 32.03% init_globals()
- 31.10% universe_init()
- 26.44% G1CollectedHeap::initialize()
- 25.84% G1CollectedHeap::expand(unsigned long, WorkerThreads*, double*)
- G1HeapRegionManager::expand_by(unsigned int, WorkerThreads*)
- 20.38% G1HeapRegionManager::expand(unsigned int, unsigned int, WorkerThreads
- 9.70% G1HeapRegionManager::commit_regions(unsigned int, unsigned long, Wo
- 8.07% G1RegionsSmallerThanCommitSizeMapper::commit_regions(unsigned in
- 7.99% G1PageBasedVirtualSpace::commit(unsigned long, unsigned long)
+ 7.92% os::commit_memory_or_exit(char*, unsigned long, unsigned l
+ 1.53% G1FromCardCache::invalidate(unsigned int, unsigned long)
- 8.73% G1RegionsSmallerThanCommitSizeMapper::commit_regions(unsigned int,
- G1PageBasedVirtualSpace::commit(unsigned long, unsigned long)
+ 8.55% os::commit_memory_or_exit(char*, unsigned long, unsigned long
- 1.83% G1CollectedHeap::new_heap_region(unsigned int, MemRegion)
- G1HeapRegion::G1HeapRegion(unsigned int, G1BlockOffsetTable*, MemRegio
- 1.37% G1HeapRegionRemSet::G1HeapRegionRemSet(G1HeapRegion*, G1CardS
0.70% G1CardSetMemoryManager::G1CardSetMemoryManager(G1CardSetCo
+ 4.81% __memset_avx2_unaligned_erms
+ 0.65% G1HeapRegionManager::initialize_regions(unsigned int, unsigned int)
+ 3.35% Metaspace::global_initialize()
0.60% MetaspaceShared::initialize_shared_spaces()
Reducing -Xms helps:
$ hyperfine -w 10 -r 10 "build/linux-x86_64-server-release/images/jdk/bin/java -XX:+UseG1GC -Xms128m -Xmx2g Hello"
Benchmark 1: build/linux-x86_64-server-release/images/jdk/bin/java -XX:+UseG1GC -Xms128m -Xmx2g Hello
Time (mean ± σ): 23.4 ms ± 0.4 ms [User: 12.6 ms, System: 18.5 ms]
Range (min … max): 22.9 ms … 24.1 ms 10 runs
While we should really consider to trim the default initial heap size (JDK-8348278), it would not help if user specifies Xms. So, it would be great to see if we can improve this code path across large initial heap sizes.
- relates to
-
JDK-8348278 Trim InitialRAMPercentage to improve startup in default modes
-
- Open
-