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

本文探讨了Java应用程序中JNI资源的正确释放方法。通过使用Runtime.addShutdownHook注册钩子线程来确保静态加载的JNI资源在JVM退出时能够得到及时释放。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

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()方法。

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();
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

10km

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值