如何在应用服务器中统计Java HeapSpace异常指标?
解决Payara环境下监控Java HeapSpace异常次数的方案
方法一:用Java Agent字节码增强统计异常次数
直接通过字节码修改java.lang.OutOfMemoryError的构造逻辑,统计HeapSpace类型的OOM次数,还能把计数器暴露给Prometheus或者JMX:
- 写个简单的Java Agent,用ByteBuddy或ASM这类工具,在OOM的构造方法里插入计数逻辑,过滤出
Java heap space相关的异常 - 核心代码示例(用ByteBuddy):
public class OOMCounterAgent { public static void premain(String agentArgs, Instrumentation inst) { inst.addTransformer((loader, className, classBeingRedefined, protectionDomain, classfileBuffer) -> { if ("java/lang/OutOfMemoryError".equals(className)) { return new ByteBuddy() .redefine(OutOfMemoryError.class) .constructor(ElementMatchers.any()) .intercept(MethodDelegation.to(OOMInterceptor.class).andThen(SuperMethodCall.INSTANCE)) .make() .getBytes(); } return classfileBuffer; }); } } public class OOMInterceptor { private static final AtomicLong heapOOMCount = new AtomicLong(0); public static void intercept() { // 通过栈回溯判断是否是HeapSpace OOM for (StackTraceElement elem : new Throwable().getStackTrace()) { if (elem.getClassName().contains("HeapSpace")) { heapOOMCount.incrementAndGet(); break; } } } // 暴露成JMX MBean,让Prometheus JMX Exporter抓取,或者直接推指标 public static long getHeapOOMCount() { return heapOOMCount.get(); } } - 把Agent打包成jar,在Payara启动参数里加
-javaagent:/path/to/your-agent.jar,之后就能通过JMX或者自定义的Prometheus指标接口拿到计数
方法二:监控Payara日志统计次数
旧版本Payara发生HeapSpace OOM时,会把异常信息写到domain/logs/server.log里,直接监控日志计数:
- 用脚本或者日志工具(比如Promtail)抓取日志里包含
java.lang.OutOfMemoryError: Java heap space的行数 - 示例shell脚本(可以用cron定时执行推到Prometheus Pushgateway):
#!/bin/bash LOG_PATH="/opt/payara/domain/logs/server.log" OOM_COUNT=$(grep -c "java.lang.OutOfMemoryError: Java heap space" $LOG_PATH) curl -X POST -H "Content-Type: text/plain" --data-binary "payara_heap_oom_total $OOM_COUNT" http://pushgateway:9091/metrics/job/payara_log_monitor - 这种方法简单直接,不需要修改代码,适合快速落地
方法三:用JVM Flight Recorder(JFR)抓OOM事件
如果你的旧版本Payara支持JFR(部分版本默认带),可以通过JFR记录OOM事件:
- 启动Payara时加参数:
-XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:StartFlightRecording=duration=24h,filename=payara_oom.jfr - 可以用JFR的API实时解析事件计数,或者事后分析JFR文件提取OOM次数,再把计数转成Prometheus指标
方法四:Web应用全局Filter补充统计
如果你的业务都是Web请求,可以写全局Servlet Filter捕获请求链路中的HeapSpace OOM:
- 示例Filter代码:
@WebFilter("/*") public class OOMMonitorFilter implements Filter { private static final AtomicLong heapOOMCount = new AtomicLong(0); @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { try { chain.doFilter(req, res); } catch (OutOfMemoryError oom) { if (oom.getMessage() != null && oom.getMessage().contains("Java heap space")) { heapOOMCount.incrementAndGet(); } throw oom; // 不要吞异常,保证应用正常处理 } } // 暴露JMX或Prometheus指标 public static long getHeapOOMCount() { return heapOOMCount.get(); } } - 注意:这个方法只能捕获Web请求里的OOM,后台线程(比如定时任务)的OOM抓不到,适合作为补充方案
内容的提问来源于stack exchange,提问作者Gui13
相关产品推荐
相关产品推荐

