在日常项目运作中,有时我们需要将JVM的信息以我们期望的方式输出到日志中,然后对日志对日志进行实时监控。
1.JVM监控日志
#jvm-monitor-digest.log#
说明:记录了jvm中的一些堆内存和线程信息以及堆外内存,例
2014-07-10 00:00:06,599 INFO JVM INFO - (1325.5,5390)(7.4,135,614,3601)(5.46,5390)
2014-07-10 00:00:36,599 INFO JVM INFO - (1745.07,5390)(7.4,135,614,3601)(5.46,5390)
格式:(used_heap,max_heap)(current_thread_cpu_time,daemon_thread_count,total_thread_count,total_started_thread_count)(non_heap_reserved_memory,non_heap_max_memory)
2.实现原理
创建一个守护线程定时(每隔30s)统计堆内存,线程信息,堆外内存,并输出。
堆内存信息:
直接使用java内存管理Bean MemoryMXBean获取堆内存信息。
MemoryMXBean获取方法:
private static final MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
线程信息:
直接使用java线程管理Bean ThreadMXBean获取堆内存信息。
MemoryMXBean获取方法:
private static final ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
格式:(used_heap,max_heap)(current_thread_cpu_time,daemon_thread_count,total_thread_count,total_started_thread_count)(non_heap_reserved_memory,non_heap_max_memory)
堆外内存:
这里是指狭义的堆外内存,是指java.nio.DirectByteBuffer在创建的时候分配的内存,也叫Direct memory。堆外内存信息可以通过反射获取java.nio.Bits对应的字段maxMemory和reservedMemory,注意这两个字段的单位是bytes。
http://www.open-open.com/lib/view/open1431570358826.html
代码
public class JvmMonitor
{
protected static final Log logger = LogFactory.getLog("jvm-monitor-digest");
private static final String SPLITTER = ",";
private static final DecimalFormat decimalformat = new DecimalFormat("#.##");
private static final MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
private static final ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
private static Field maxDirectedMemoryField;
private static Field reservedDirectedMemoryField;
public JvmMonitor()
throws Exception
{
Class clz = Class.forName("java.nio.Bits");
maxDirectedMemoryField = clz.getDeclaredField("maxMemory");
maxDirectedMemoryField.setAccessible(true);
reservedDirectedMemoryField = clz.getDeclaredField("reservedMemory");
reservedDirectedMemoryField.setAccessible(true);
}
public void start() {
Thread monitor = new Thread() {
public void run() {
try {
while (true) {
JvmMonitor.logger.info(JvmMonitor.this.getJVMInfo());
sleep(30000L);
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
monitor.setDaemon(true);
monitor.setName("JVM INFO");
monitor.start();
}
private String getJVMInfo() {
MemoryUsage memoryUsage = memoryMXBean.getHeapMemoryUsage();
StringBuilder sb = new StringBuilder();
sb.append("(");
sb.append(formatValue(memoryUsage.getUsed())).append(",");
sb.append(formatValue(memoryUsage.getMax()));
sb.append(")");
sb.append("(");
sb.append(formatNanosecond(threadMXBean.getCurrentThreadCpuTime())).append(",");
sb.append(threadMXBean.getDaemonThreadCount()).append(",");
sb.append(threadMXBean.getThreadCount()).append(",");
sb.append(threadMXBean.getTotalStartedThreadCount());
sb.append(")");
sb.append(getDirectedMemoryInfo());
return sb.toString();
}
private String getDirectedMemoryInfo()
{
StringBuilder sb = new StringBuilder();
Long maxMemoryValue = Long.valueOf(0L); Long reservedMemoryValue = Long.valueOf(0L);
try {
maxMemoryValue = (Long)maxDirectedMemoryField.get(null);
reservedMemoryValue = (Long)reservedDirectedMemoryField.get(null);
}
catch (Exception e) {
}
sb.append("(");
sb.append(formatValue(reservedMemoryValue.longValue()));
sb.append(",");
sb.append(formatValue(maxMemoryValue.longValue()));
sb.append(")");
return sb.toString();
}
private static String formatValue(long value)
{
Double tempValue = Double.valueOf(new Double(value).doubleValue() / 1024.0D / 1024.0D);
return decimalformat.format(tempValue);
}
private String formatNanosecond(long value) {
Double tempValue = Double.valueOf(new Double(value).doubleValue() / 1000000000.0D);
return decimalformat.format(tempValue);
}
}