JVM如何获取当前容器的资源限制
本文是《容器中的Java》系列文章之 1/n ,欢迎关注后续连载 :) 。
最近同事说到Java的 ParallelGCThreads 参数,我翻了下jdk8的代码,发现 ParallelGCThreads 的参数默认值如下:
- 如果cpu核心数目少于等于8,则GC线程数量和CPU数一致
- 如果cpu核心数大于8,则前8个核,每个核心对应一个GC线;其他核,每8个核对应5个GC线程
但是被提醒,发现即使在分配4核的容器上,GC线程数也为38。然后就想到应该和容器的资源限制有关——jvm可能无法觉察到当前容器的资源限制。
翻了下代码,发现最新版本的java是能感知容器的资源限制的,就按照jdk版本再翻了下代码:
线上的jdk(jdk8u144)
写一个sleep 1000s的程序,用于查看JVM的线程数量:
1 | ./jdk1.8.0_144/bin/java -XX:+UseG1GC -XX:+ParallelRefProcEnabled Main |
然后查看GC线程数目:
1 | jstack $pid | grep 'Parallel GC Threads' | wc -l |
一算就知道物理机器有56个核心(8+(56-8)*5/8=38)
然后使用+PrintFlagsFinal
看下参数:
1 | ./jdk1.8.0_144/bin/java -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal -version | grep ParallelGCThreads |
看来jdk8u144并无法读取容器配额。
jdk 8u191
然后发现,从jdk 8u191版本开始,Java就可以读取容器配额了:
运行同样的程序:
1 | ./jre1.8.0_191/bin/java -XX:+UseG1GC -XX:+ParallelRefProcEnabled Main |
查看实际参数:
1 | ./jre1.8.0_191/bin/java -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal -version | grep ParallelGCThreads |
另外,jdk 8u191引入了PrintContainerInfo参数:
1 | ./jre1.8.0_191/bin/java -XX:+UnlockDiagnosticVMOptions -XX:+PrintContainerInfo -version |
可以看到,获取的内存限制、可用CPU数目都是对的了。
如何获取容器资源配额呢?
结合这个日志和代码,我们也可以看到如何获取容器配额:
首先从/proc/self/mounts中读取对应的资源的mount位置,比如cpu就是在/sys/fs/cgroup/cpu,cpuacct
:
1 | cat /proc/mounts | grep -E -w '(cpu|memory)' |
对于内存:
1 | cat /sys/fs/cgroup/memory/memory.limit_in_bytes |
对于cpu资源:
其一,可以通过quota/period来算:
1 | cat /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_period_us #单CPU总时间片配额,微秒 |
比如上面就表示分配了4核。
也可以通过cpu.shares来获取:
1 | cat /sys/fs/cgroup/cpu,cpuacct/cpu.shares |
不过这个值是cpu占用份额,无法根据这个算出来可用cpu数量,所以基本没用…
JVM如何获取当前容器的资源限制
https://robberphex.com/java-and-docker-memory-and-cpu-limits/