OpenJDK进程实际可用CPU核数需查cgroup限制:v1看cpu.cfs_quota_us/cpu.cfs_period_us,v2看cpu.max;JVM 10+默认通过UseContainerSupport感知配额,但显式设置-XX:ActiveProcessorCount会覆盖该行为。

确认 OpenJDK 进程实际可见的 CPU 核数
容器或 cgroup 限制下,lscpu 或 nproc 返回的是宿主机总核数,不是 Java 进程能用的配额。必须看进程视角的可用 CPU —— 即 /sys/fs/cgroup 下的限制值。
- 先查 Java 进程 PID:
ps -eo pid,comm,args | grep java | grep -v grep - 再定位其 cgroup 路径:
cat /proc/<pid>/cgroup | grep -E 'cpu|cpuset'</pid>(注意 v1 和 v2 路径不同) - 若为 cgroup v1(常见于 CentOS 7/RHEL 7):
- CPU 配额:读
/sys/fs/cgroup/cpu,cpuacct/<path>/cpu.cfs_quota_us</path>和cpu.cfs_period_us,配额 =cpu.cfs_quota_us / cpu.cfs_period_us(如 200000/100000 = 2 核) - 若
cpu.cfs_quota_us = -1,表示无限制
- CPU 配额:读
- 若为 cgroup v2(Ubuntu 22.04+/RHEL 8+ 默认):
- 查
/sys/fs/cgroup/<path>/cpu.max</path>,格式为"max 100000"或"200000 100000",后者即 quota/period
- 查
-
Runtime.getRuntime().availableProcessors()在 JDK 10+ 会自动读取 cgroup 限制,但前提是 JVM 启动时未显式设置-XX:ActiveProcessorCount—— 设了就绕过 cgroup,返回错误值
确认 OpenJDK 进程实际可用的内存上限
Java 进程看到的堆内存(-Xmx)和它被允许使用的物理内存(cgroup memory limit)是两回事。OOM Killer 杀进程前看的是后者,不是前者。
- 同样从
/proc/<pid>/cgroup</pid>找 memory controller 路径 - cgroup v1:读
/sys/fs/cgroup/memory/<path>/memory.limit_in_bytes</path>(-1表示无限制) - cgroup v2:读
/sys/fs/cgroup/<path>/memory.max</path>(max表示无限制) - JDK 自身行为:
- JDK 8u191+ / JDK 10+ 默认启用
+UseContainerSupport,会自动按 cgroup limit 设置MaxRAMPercentage(默认 25%),除非你手动指定-Xmx - 若设了
-Xmx,JVM 就无视 cgroup limit —— 但宿主机仍会按 limit 杀你,导致“明明 -Xmx 没超,却被 OOM Kill”
- JDK 8u191+ / JDK 10+ 默认启用
- 验证是否生效:启动 Java 时加
-XX:+PrintGCDetails -XX:+PrintGCTimeStamps,看 GC 日志里 InitialHeapSize / MaxHeapSize 是否接近 cgroup limit × 0.25
为什么 free -h 和 jstat -gc 看到的内存对不上
这是最常踩的坑:系统级内存、JVM 堆内存、JVM 直接内存(Direct Buffer)、JIT 编译代码、线程栈等加起来才等于进程 RSS。只盯 jstat 会漏掉大头。
-
free -h的available是系统空闲内存,跟 Java 进程无关;Mem: total是宿主机总内存,不是你的配额 -
jstat -gc <pid></pid>只反映堆内各代使用量,不包括 Metaspace、Compressed Class Space、Direct Buffer、线程栈(每个线程默认 1MB) - 真正可比的是:
ps -o pid,rss,comm -p <pid></pid>的RSS值 vs cgroup memory limit - 若 RSS 接近 limit,但
jstat显示堆只用了 30%,大概率是 Direct Buffer 泄漏(ByteBuffer.allocateDirect()未 clean)或大量线程未回收
检查 OpenJDK 是否识别到容器配额的快捷方式
不用翻 cgroup 路径,直接看 JVM 启动日志或运行时输出:
- 启动时加
-XX:+PrintFlagsFinal -version | grep -E "ActiveProcessor|MaxRAM|UseContainerSupport":-
UseContainerSupport := true→ 已启用容器感知 -
ActiveProcessorCount应等于 cgroup CPU 配额(非宿主机核数) -
MaxRAMPercentage默认 25.0,若没设-Xmx,则MaxHeapSize≈ limit × 0.25
-
- 运行中调用:
jinfo -flag ActiveProcessorCount <pid></pid>,返回值应与 cgroup 配额一致 - 如果返回值仍是宿主机核数(比如 64),说明:
- JDK 版本太老(
- 显式设置了
-XX:ActiveProcessorCount - cgroup 路径没挂载(Docker 未加
--cgroup-parent或 systemd 服务未配置MemoryLimit/CPUQuota)


















