Jvm的PerfData
Java系统的监控经常是通过JMX的,最近几年也比较流行使用Dropwizard和SpringMetrics的集成。
Jvm自身有一个叫PerfData的指标集,是使用mmap来存储的,jstat就是基于它的。
我们平时在生产环境中使用jstat来观察JVM的GC情况(时间、次数、分代大小),
但是PerfData还有很多其他指标,而且非常有用。
下面就来介绍一下PerfData。
基本概念
Perfdata里大概有200-300个指标,有数值类型的,也有字符串的(比如gc cause)。
你可以使用MonitoredVm.findByPattern(““)来获取全部指标的列表,也可以用名字获取单个指标。
JVM运行时,不断在内存中更新指标值,通过mmap映射到/tmp/hsperfdata_user/pid的文件中。
这个文件的大小是32K,mmap文件默认是30s才刷新同步,perfdata的文件延迟是特殊控制的。
如果你使用过mmap就会知道有个force接口,可以强制同步更新,perfdata的更新频率在100ms以内。
提一个题外话,jvm启动后会生成一个/tmp/.javapidxxxxx的文件,这个文件是一个socket,
常用的jstack、jmap、jcmd都是通过他来和jvm通讯的,不要和perfdata的文件弄混淆了。
获取指标的方法
因为有一个独立的mmap文件存在,所以想要获取指标并不需要和jvm进行通讯,
只要你的程序有权限读取这个文件即可,当然读取这个文件最好使用java提供的类库,方便一些。
如果你想自己解析,可以参考这个类的实现,sun.jvmstat.perfdata.monitor.v2_0.PerfDataBuffer。
特别注意一下其中的ByteOrder,字节存储机制主要有两种:Big-endian和Little-endian。
相关细节就不展开讲了,自行查阅资料吧。
Arguments JPS_ARGUMENTS = new Arguments(new String[] {"-l"});
MonitoredHost monitoredHost = MonitoredHost.getMonitoredHost(JPS_ARGUMENTS.hostId());
MonitoredVm vm = this.monitoredHost.getMonitoredVm(new VmIdentifier("//" + pid + "?mode=r"), 1000);
这段代码你可以在jstat的源码中找到,根据需要自行修改。
指标
这几百个指标我们也并非都关心,有很多指标的含义都搞不清楚,需要读读JVM的源码才能知道。
今年年初我们在开发基于Perfdata的JVM性能指标监控时,进行了一些整理工作,主要采集了三五十个指标。
具体指标的含义今后会更新,这里只列一下大致的分类。
1、TLAB:
- 1.1、sun.gc.tlab.alloc
- 1.2、sun.gc.tlab.allocThreads
- 1.3、sun.gc.tlab.fills
- 1.4、sun.gc.tlab.gcWaste
2、Threshold:
- 2.1、sun.gc.policy.tenuringThreshold
- 2.2、sun.gc.policy.maxTenuringThreshold
- 2.3、sun.gc.policy.incrementTenuringThresholdForGcCost
- 2.4、sun.gc.policy.decrementTenuringThresholdForGcCost
- 2.5、sun.gc.policy.decrementTenuringThresholdForSurvivorLimit
3、Thread:
- 3.1、java.threads.live
- 3.2、java.threads.started
4、Safepoint:
- 4.1、sun.rt.safepoints
- 4.2、sun.rt.safepointTime
- 4.3、sun.rt.safepointSyncTime
5、Memory:
- 5.1、sun.gc.generation.0.space.X.used
- 5.2、sun.gc.generation.0.space.X.capacity
6、Lock:
- 6.1、sun.rt._sync_ContendedLockAttempts
- 6.2、sun.rt._sync_Parks
- 6.3、sun.rt._sync_Notifications
- 6.4、sun.rt._sync_FutileWakeups
- 6.5、sun.rt._sync_Inflations
- 6.6、sun.rt._sync_Deflations
7、GC:
- 7.1、sun.gc.collector.X.invocations
- 7.2、sun.gc.collector.X.time
- 7.3、sun.gc.policy.avgMinorPauseTime(avgMajorPauseTime)
- 7.4、sun.gc.policy.avgPromotedAvg
- 7.5、sun.gc.policy.avgSurvivedAvg
- 7.6、sun.gc.policy.gcTimeLimitExceeded
- 7.7、sun.gc.policy.survivorOverflowed
8、Compile:
- 8.1、java.ci.totalTime
- 8.2、sun.ci.totalCompiles
- 8.3、sun.ci.osrTime
- 8.4、sun.ci.osrCompiles
- 8.5、sun.ci.totalBailouts
- 8.6、sun.ci.totalInvalidates
9、Class:
- 9.1、sun.cls.time
- 9.2、java.cls.loadedClasses
- 9.3、java.cls.unloadedClasses
10、AgeTable:
- 10.1、sun.gc.generation.0.agetable.bytes.XX
选取的这些指标主要是为了监控性能和性能调优。
除了指标类型的监控,也可以尝试使用一下jitwatch和jfr,都会有一些意想不到的收获。
Flags
Jvm在启动时,可以配置很多参数,这个参数也是有API可以获取的。
VirtualMachine vm = VirtualMachine.attach(pid);
HotSpotVirtualMachine hvm = (HotSpotVirtualMachine) vm;
InputStream in = hvm.executeJCmd("VM.flags -all");
这个代码你可以从Jcmd的源码中找到,网上能搜到VM.flags,很少有人提到-all这个参数。
看看你的Jvm到底都有哪些flag,你又知道多少flag的含义呢。