前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >java(JVM)结束时释放JNI资源(Runtime.addShutdownHook)

java(JVM)结束时释放JNI资源(Runtime.addShutdownHook)

作者头像
10km
发布2022-05-07 10:13:01
8790
发布2022-05-07 10:13:01
举报
文章被收录于专栏:10km的专栏10km的专栏

如下代码中cmjnidrv是一个动态库,CodeCacheManager在类加载时就自动将cmjnidrv加载进来。cmjnidrv中有多个独立的线程在运行并申请了大量的内存. release()是个native方法,用于释放cmjnidrv中的申请资源并中止cmjnidrv中的线程。 为了保证在java应用结束的时候cmjnidrv的资源能被正确释放,就必须确保release()被调用。

代码语言:javascript
复制
public class CodeCacheManager{
    private static final Logger logger = LoggerFactory.getLogger(CodeCacheManager.class);

    static{
        System.loadLibrary("cmjnidrv"); 
    }
    private static final CodeCacheManager instance=new CodeCacheManager();
    static public CodeCacheManager getInstance(){
        return instance;
    }
    private CodeCacheManager(){
    }
    /**
     * 释放所有JNI资源
     */
    public native static  void release();
    /* (非 Javadoc)
     * @see java.lang.Object#finalize()
     */
    @Override
    protected void finalize() throws Throwable {
        logger.info("release JNI resoure...");
        release();
        logger.info("release JNI resoure finished");
    }
}

原本的设计是在finalize()方法中执行release()方法。这样CodeCacheManager对象被垃圾回收器回收的时候会自动释放JNI资源,但是CodeCacheManager是个单例(singleton)的class,instance静态成员变量永远保持着对单例对象的引用,所以JAVA的垃圾回收器永远不可能去调用finalize()。 所以这个方案不可行,事实也是正是这样,执行shutdown.sh停止tomcat服务器时,执行top命令显示,java进程仍然在运行中,而且占用着大量的内存。也没有log “release JNI resoure…”输出,显示finalize()方法没有被执行。 所以如何在JVM结束时释放静态加载的动态库中的资源还是得另想办法。

这时 void java.lang.Runtime.addShutdownHook(Thread hook)就派上用场了。下面是addShutdownHook方法的原文说明(部分):

Registers a new virtual-machine shutdown hook. The Java virtual machine shuts down in response to two kinds of events: The program exits normally, when the last non-daemon thread exits or when the exit (equivalently, System.exit) method is invoked, or The virtual machine is terminated in response to a user interrupt, such as typing ^C, or a system-wide event, such as user logoff or system shutdown.

当JVM结束时(正常结束,或被Ctrl-C中止,或因系统事件(如logoff ,shutdown))会执行用addShutdownHook方法注册的线程。 所以确保静态加载的JNI资源释放的办法,就是在加载动态库的时候,向JVM注册一个hook线程,用于执行release()方法。

代码语言:javascript
复制
public class CodeCacheManager{
    private static final Logger logger = LoggerFactory.getLogger(CodeCacheManager.class);

    static{
        // add hook for release JNI resource on JVM shutdown 
        Runtime.getRuntime().addShutdownHook(new Thread (){
            @Override
            public void run() {
                logger.info("release JNI resoure...");
                relase();
                logger.info("release JNI resoure finished");
            }});
        System.loadLibrary("cmjnidrv"); 
    }
    private static final CodeCacheManager instance=new CodeCacheManager();
    static public CodeCacheManager getInstance(){
        return instance;
    }
    private CodeCacheManager(){
    }
    /**
     * 释放所有JNI资源
     */
    public native static  void release();
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016-01-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档