OSHI获取CPU使用率不准是因需两次采样差值计算,应优先用getProcessorCpuLoadBetweenTicks()并预热;内存使用率应以(getTotal()-getAvailable())/getTotal()计算;需显式引入JNA依赖并复用SystemInfo单例。

Java 用 OSHI 获取 CPU 使用率不准或为 0?
OSHI 的 CentralProcessor 默认不自动刷新采样,直接调用 getSystemCpuLoad() 或 getProcessorCpuLoadBetweenTicks() 可能返回 -1 或 0——这不是 bug,是设计使然:它需要两次采样做差值计算。
- 必须先调用一次
updateAttributes()(或让 OSHI 内部触发,比如通过getSystemCpuLoadBetweenTicks()自动触发首次采集) - 推荐用
getProcessorCpuLoadBetweenTicks(),它内部会做两次间隔采集,返回的是最近一段时间的平均负载,更稳定 - 注意:该方法首次调用仍可能返回
-1.0(因无前序快照),建议忽略首值,或预热一次再正式采集 - Linux 下若进程权限不足(如未用 root 启动),
/proc/stat读取失败会导致 CPU 负载恒为 0;Windows 和 macOS 一般无此问题
OSHI 获取内存使用率时 total / available 不一致?
OSHI 的 GlobalMemory 返回的 getTotal() 和 getAvailable() 是操作系统级真实值,但「使用率」不能简单用 (total - available) / total ——因为 Linux 有 page cache、buffers 等可回收内存,available 已经扣除了这部分,而 used 字段(如果存在)才是更贴近“应用视角”的已用内存。
- 优先用
getAvailable()和getTotal()计算:(getTotal() - getAvailable()) / getTotal(),这是最接近用户感知的“可用内存剩余”指标 - 避免用
getUsed()(某些平台返回 0 或不可靠),它在 Windows 上可能缺失,在旧版 Linux 内核中也不稳定 - 注意单位:所有值都是字节,别忘了除以
1024L * 1024 * 1024转 GB,否则显示异常大 - 频繁调用
getAvailable()不会显著影响性能,但建议 1~5 秒粒度采集,太密反而因内核统计延迟导致抖动
引入 OSHI 后启动报 NoClassDefFoundError: com.sun.jna.Native
这是典型依赖缺失:OSHI 底层依赖 JNA(Java Native Access),而新版 Maven 中央仓库的 oshi-core 默认不带 jna 传递依赖,尤其当你用 Gradle 或精简了依赖树时极易掉坑。
- Maven 用户必须显式声明
jna和jna-platform,版本需与 OSHI 兼容(例如 OSHI 6.4.x 对应 JNA 5.13.x) - Gradle 用户注意:若用了
implementation 'com.github.oshi:oshi-core:6.4.3',得补上implementation 'net.java.dev.jna:jna:5.13.0'和implementation 'net.java.dev.jna:jna-platform:5.13.0' - 打包成 fat jar 时,JNA 的 native 库(如
jna-5.13.0-native.jar)不会自动合并,得用shadowJar或spring-boot-maven-plugin正确处理资源路径 - Mac M1/M2 用户若遇到
UnsatisfiedLinkError,确认用的是 JNA 5.12.1+,旧版不支持 aarch64
监控服务长期运行后 CPU / 内存数据越来越不准?
OSHI 本身不泄漏资源,但常见误用会让 SystemInfo 实例持续持有大量 native 句柄(尤其是 CentralProcessor 和 HardwareAbstractionLayer),在容器或短生命周期应用里不明显,但在常驻 JVM 进程中积累数天后可能引发句柄耗尽或采样延迟。
立即学习“Java免费学习笔记(深入)”;
- 不要反复 new
SystemInfo()—— 它是线程安全的,全局单例复用即可 - 避免在循环里每次都调用
getHardware().getMemory()或getProcessor(),这些 getter 每次都可能重建底层代理对象;应缓存HardwareAbstractionLayer和CentralProcessor引用 - Linux 下若启用了 cgroups v2(常见于 Docker 20.10+ 或 systemd 环境),OSHI 5.x 默认无法读取容器内存限制,需升级到 OSHI 6.3+ 并启用
oshi.hardware.memory.cgroup-v2=true配置项 - 定期(如每小时)调用一次
systemInfo.getOperatingSystem().getProcessId()可触发内部状态刷新,对稳定性有隐性帮助
硬件指标不是纯数学计算,它高度依赖 OS 接口稳定性、JVM 权限、native 层兼容性。哪怕同一行代码,在 CentOS 7 容器里跑和在 macOS 本地跑,返回逻辑都可能不同——别迷信文档里的“应该”,先看日志里实际读到了什么值。










