K8s 里给 Java 服务限了 2 核 4G,容器里 nproc 返回 64,应用按核数开线程池,启动十分钟就被 OOMKilled,宿主机上进程数也飙高。

一开始怀疑是「limits 里只写了 cpu 没写 requests,调度和运行时视图都不准」,查了一圈,方向不对。

把日志和配置对完,能解释这个现象的基本就这几处。容器默认读到的是宿主机的 CPU 拓扑,nproc 不会自动按 cgroup 配额换算。少数情况下是应用的线程池大小直接取 Runtime.availableProcessors,没有读 cgroup 限制。

另外,JVM 版本较老,不认 cgroup v2 的 cpu.max。

上来先对比容器内外的 CPU 视图

nproc && cat /sys/fs/cgroup/cpu.max

接着确认 JVM 实际识别到的核数

java -XX:+PrintFlagsFinal -version | grep ActiveProcessorCount

显式指定核数并限制线程池

java -XX:ActiveProcessorCount=2 -jar app.jar

末了观察内存和线程数是否回落

kubectl top pod app-0 && ps -eLf | wc -l

改完先别撤,确认这几项。容器内 jvm 识别到 2 个处理器,线程数稳定在预期范围,Pod 连续运行一小时没有 OOMKilled,内存曲线平稳。

容易忽略的是,这类问题在容器里非常常见,上线前用 ActiveProcessorCount 或 -XX:MaxRAMPercentage 显式约束,比事后调大内存划算得多。拖得越久,排查成本越高,因为现场状态会被后续操作覆盖。

作者 9823189