jvm 通知机制

背景

最近公司在做GC方面的监控,由于堆转储方式(heap dump)对于系统损耗过大,在生产中不能使用该方式,经查阅在JDK1.7版本后,JDK新增了notification的方式,用于在各种内存变化信息时主动发送通知,该通知含有内存的详细信息,以GC通知为例,GarbageCollectionNotificationInfo中含有GC发生的起始时间,结束时间,耗时,使用算法,发生原因,各JVM内存块的init, max, committed, used的信息等,相对于被动检测来说(周期性从GarbageCollectionMXBean对象中获取JVM内存信息),这种方式具有更好的实时性,性能损耗更小。

类图

主要包括通知以及各种Bean
在这里插入图片描述

监听器

package com.peipei.jvm.notify.garbage;

import com.google.gson.Gson;
import com.sun.management.GarbageCollectionNotificationInfo;
import com.sun.management.GcInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.management.Notification;
import javax.management.NotificationListener;
import javax.management.openmbean.CompositeData;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryUsage;
import java.lang.management.RuntimeMXBean;
import java.util.Map;

/**
 * 监听器.当收到通知后由该监听器处理通知
 */
public class GarbageNotificationListener implements NotificationListener {
    private static final Logger logger = LoggerFactory.getLogger(GarbageNotificationListener.class);
    private static final Gson gson = new Gson();
    private static final RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
    private static final Long JVM_START_TIME = runtimeMXBean.getStartTime();

    /**
     * @param notification
     * @param handback
     */
    public void handleNotification(Notification notification, Object handback) {
        //  垃圾回收的通知信息
        GarbageCollectionNotificationInfo info = GarbageCollectionNotificationInfo.from((CompositeData) notification.getUserData());
        // GC的相关信息
        GcInfo gcInfo = info.getGcInfo();
        logger.info("垃圾回收信息: {}", gson.toJson(gcInfo));
        // 垃圾回收后的内存信息
        Map<String, MemoryUsage> memoryUsageBeforeGcMap = gcInfo.getMemoryUsageBeforeGc();
        logger.info("垃圾回收前内存信息: {}", gson.toJson(gcInfo));
        // 垃圾回收后的内存信息
        Map<String, MemoryUsage> memoryUsageAfterGcMap = gcInfo.getMemoryUsageAfterGc();
        logger.info("垃圾回收后内存信息: {}", gson.toJson(gcInfo));

        //  GC发生的开始时间,是相对于JVM启动时间的相对值
        long gcStartTime = gcInfo.getStartTime() + JVM_START_TIME;
        //  GC发生的结束时间,是相对于JVM启动时间的相对值
        long gcEndTime = gcInfo.getEndTime();
        // GC耗时
        long duration = gcInfo.getDuration();

        logger.info("GC发生于{}, 结束于{}, 耗时 {}ms", gcStartTime, gcEndTime, duration);
    }
}

过滤器

package com.peipei.jvm.notify.garbage;

import com.sun.management.GarbageCollectionNotificationInfo;

import javax.management.Notification;
import javax.management.NotificationFilter;

/**
 * 过滤器,JVM会将所有类型的通知都发送事件过来
 * 此处将过滤掉除垃圾回收通知之外的其他所有通知信息
 */
public class GarbageNotificationFilter implements NotificationFilter {

    /**
     * 除了类型为垃圾回收之外的通知都不会接收
     *
     * @param notification 通知
     * @return
     */
    public boolean isNotificationEnabled(Notification notification) {
        return GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION.equals(notification.getType());
    }
}

注册事件

package com.peipei.jvm.notify.garbage;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.management.NotificationEmitter;
import javax.management.NotificationFilter;
import javax.management.NotificationListener;
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.util.List;

public class GarbageNotificationRegister {
    private static final Logger logger = LoggerFactory.getLogger(GarbageNotificationRegister.class);

    //  获取运行JVM的垃圾回收器相关的管理的bean
    private static List<GarbageCollectorMXBean> garbageCollectorMXBeanList = ManagementFactory.getGarbageCollectorMXBeans();

    /**
     * 初始化,注册垃圾回收的监听器
     */
    public static void init (){
        for (GarbageCollectorMXBean bean : garbageCollectorMXBeanList){
            // 发射器,发生GC时,发射一个通知到监听器中
            NotificationEmitter emitter = (NotificationEmitter)bean;

            // 创建监听器对象
            NotificationListener listener = new GarbageNotificationListener();
            // 创建过滤器对象
            NotificationFilter filter = new GarbageNotificationFilter();
            emitter.addNotificationListener(listener, filter, bean);
        }
    }
}

启动程序

package com.peipei.jvm.notify.garbage.main;

import com.peipei.jvm.notify.garbage.GarbageNotificationRegister;

import java.util.ArrayList;
import java.util.List;

public class Main {
    private static final List<byte[]> list = new ArrayList();

    static {
        GarbageNotificationRegister.init();
    }

    public static void main(String[] args) {
        while (true){
            list.add(new byte[1024 * 1024 * 5]);
            Runtime.getRuntime().gc();
        }
    }
}

观擦控制台不断的打印GC
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值