×
Community Blog How Does JVM Obtain the Resource Limit of the Current Container?

How Does JVM Obtain the Resource Limit of the Current Container?

This entry in the Java in Container series discusses the default value of ParallelGCThreads.

By Bubi

This is the first article of the Java in Container series. You are welcome to follow the series. 😊

Recently, my colleague talked about Java's ParallelGCThreads parameter. I went through the JDK 8 code and found that the default value of ParallelGCThreads is:

  • If the number of CPU cores is less than or equal to 8, the number of GC threads is the same as the number of CPUs.
  • If the number of CPU cores is greater than 8, each of the first 8 cores corresponds to a GC thread. For other cores, every 8 cores correspond to 5 GC threads.

However, the number of GC threads is found to be 38, even on a container with 4 cores allocated. Then, it occurred to me that it should be related to the resource limit of the container. The JVM may not be aware of the resource limit of the current container.

After looking through the code, I found that the latest version of Java is aware of the resource limit of the container, so I went through the code again according to the JDK version:

Online JDK (jdk8u144)

Write a sleep 1000s program to check the number of threads in the JVM:

./jdk1.8.0_144/bin/java -XX:+UseG1GC -XX:+ParallelRefProcEnabled Main

Then, look at the number of GC threads:

$ jstack $pid | grep 'Parallel GC Threads' | wc -l
38

The physical machine has 56 cores (8 + (56 - 8) * 5/8 = 38).

Then, use the +PrintFlagsFinal to look at the following parameter:

$ ./jdk1.8.0_144/bin/java -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal  -version | grep ParallelGCThreads
uintx ParallelGCThreads          =38                     {product}

It seems that jdk8u144 can't help read the container quota.

JDK 8u191

Then, I found Java can read the container quota from jdk 8u191:

Run the same program:

./jre1.8.0_191/bin/java -XX:+UseG1GC -XX:+ParallelRefProcEnabled Main
$ jstack $pid | grep 'Parallel GC Threads' | wc -l
4

View the actual parameter:

$ ./jre1.8.0_191/bin/java -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal  -version | grep ParallelGCThreads
uintx ParallelGCThreads         =4                   {product}

In addition, JDK 8u191 introduces the PrintContainerInfo parameter:

$ ./jre1.8.0_191/bin/java -XX:+UnlockDiagnosticVMOptions -XX:+PrintContainerInfo -version
OSContainer::init: Initializing Container Support
Path to /memory.limit_in_bytes is /sys/fs/cgroup/memory/memory.limit_in_bytes
Memory Limit is: 10737418240
Path to /cpu.cfs_quota_us is /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us
CPU Quota is: 400000
Path to /cpu.cfs_period_us is /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_period_us
CPU Period is: 100000
Path to /cpu.shares is /sys/fs/cgroup/cpu,cpuacct/cpu.shares
CPU Shares is: 681
CPU Quota count based on quota/period: 4
CPU Share count based on shares: 1
OSContainer::active_processor_count: 4
Path to /cpu.cfs_quota_us is /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us
CPU Quota is: 400000
Path to /cpu.cfs_period_us is /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_period_us
CPU Period is: 100000
Path to /cpu.shares is /sys/fs/cgroup/cpu,cpuacct/cpu.shares
CPU Shares is: 681
CPU Quota count based on quota/period: 4
CPU Share count based on shares: 1
OSContainer::active_processor_count: 4
……
java version "1.8.0_191"
Java(TM) SE Runtime Environment (build 1.8.0_191-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.191-b12, mixed mode)

As you can see, the obtained memory limit and the number of available CPUs are correct.

How Do We Obtain the Resource Quota of a Container?

Combining this log and code, we can see how to obtain the container quota:

First, read the location where the corresponding resources are mounted. For example, the CPU is in /sys/fs/cgroup/cpu,cpuacct:

$ cat /proc/mounts  | grep -E -w '(cpu|memory)'
cgroup /sys/fs/cgroup/memory cgroup ro,nosuid,nodev,noexec,relatime,memory 0 0
cgroup /sys/fs/cgroup/cpu,cpuacct cgroup ro,nosuid,nodev,noexec,relatime,cpu,cpuacct 0 0

For memory:

$ cat /sys/fs/cgroup/memory/memory.limit_in_bytes
10737418240

For CPU resources:

First, you can use the quota/period:

$ cat /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_period_us # the total time slice quota per CPU, in microseconds
100000
$ cat /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us # the CPU time that the container can occupy in the time slice
400000

For example, the example above indicates that 4 cores are allocated.

You can also use cpu.shares:

$ cat /sys/fs/cgroup/cpu,cpuacct/cpu.shares
681

However, this value is the CPU share, so there is no exact number of available CPUs based on this value, which means it is basically useless.

Summary

Use the jdk 8u191 or newer version.

0 1 0
Share on

You may also like

Comments