Java - 避免使用finalizer
Finalizers are unpredictable ,often dangerous ,and generally unnecessary.
在Java中,GC会自动回收不可达对象相关的空间,而不需要程序员做相关的工作。
对于非内存资源,我们通常使用try-finally语句块进行释放。
finalizer不保证立即执行。
从一个对象编程不可达状态到调用finalizer,这段时间是任意的。
即,对时间敏感的操作不能在finalizer中进行。
never do anything time-critical in finalizer.
比如对一些资源对象进行close,file descriptor是有限资源,不及时关闭的后果很严重。
(PS:话说AutoCloseable的author也是Josh Bloch。)
哪些finalizer会及时得到执行,这个问题主要依赖于GC算法。
但GC算法在不同的JVM中的表现或多或少会不一样(我做过的项目都是用Hotspot...)。
一个程序可能在开发时运行得不错,而换了个环境可能会无法正常运行。
(比如finalizer的优先级太低,一直没得到回收,回收速度跟不上创建速度。)
不仅不保证finalizer执行的及时性,而且也不保证finalizer执行的可能性。
finalizer有可能根本得不到执行。
比如,很多不可达对象的finalizer尚未得到执行,此时程序被终止。
Never depend on a finalizer to update critical persistent state.
也不要期待以下方法为finalizer的执行提供保障:
System.gc();
System.runFinalization();
Runtime.runFinalizersOnExit(true);
System.runFinalizersOnExit(true);
值得一提的是,如果未捕获的异常在finalizer中抛出,这个异常会被无视掉,而且连stack trace都不会打印出来。
另外,finalizer有非常严重的性能损耗,这种东西最好尽量避免。
如果某个对象封装的资源(比如文件或者线程)需要终止,此时也不要指望finalizer。
而是提供一个显示的close方法(explicit termination method),并且加入一个记录资源可用状态的私有域。
那finalizer到底有什么意义?
当忘记调用close方法时,finalizer可以当作最后的防线(原话是safety net,即安全网)。
比如FileInputStream的close方法和finalizer,当私有的FileDescriptor不为空并且也不属于java.lang.System#in时调用显示的close方法:/**
* Ensures that the <code>close</code> method of this file input stream is
* called when there are no more references to it.
*
* @exception IOException if an I/O error occurs.
* @see java.io.FileInputStream#close()
*/
protected void finalize() throws IOException {
if ((fd != null) && (fd != FileDescriptor.in)) { /*
* Finalizer should not release the FileDescriptor if another
* stream is still using it. If the user directly invokes
* close() then the FileDescriptor is also released.
*/
runningFinalize.set(Boolean.TRUE);
try {
close();
} finally {
runningFinalize.set(Boolean.FALSE);
}
}
}处理本地对等体(native peer)。
之前没有太关注"本地对等体"这个词汇。
本地对等体是一个native对象,普通对象通过本地方法委托给一个本地对象。
GC无法回收本地对等体,当本地对等体的java对等体被回收的时候,本地对等体不会被处理。
如果本地对等体不用有关键资源(critical resource),finalizer可以胜任这项工作。
PS:对于本地对等体的解释,可以参考下面一段话:
一个AWT组件通常是一个包含了对等体接口类型引用的组件类。这个引用指向本地对等体实现。
java.awt.Label为例,它的对等体接口是LabelPeer。LabelPeer是平台无关的。
在不同平台上,AWT提供不同的对等体类来实现LabelPeer。在Windows上,对等体类是WlabelPeer,它调用JNI来实现label的功能。
这些JNI方法用C或C++编写。它们关联一个本地的label,真正的行为都在这里发生。
作为整体,AWT组件由AWT组件类和AWT对等体提供了一个全局公用的API给应用程序使用。
一个组件类和它的对等体接口是平台无关的。底层的对等体类和JNI代码是平台相关的。(An AWT component is usually a component class which holds a reference with a peer interface type. This reference points to a native peer implementation.
Take java.awt.Label for example, its peer interface is LabelPeer.
LabelPeer is platform independent. On every platform, AWT provides different peer class which implements LabelPeer. On Windows, the peer class is WlabelPeer, which implement label functionalities by JNI calls.
These JNI methods are coded in C or C++. They do the actual work, interacting with a native label.
Let's look at the figure.
You can see that AWT components provide a universal public API to the application by AWT component class and AWT peers. A component class and its peer interface are identical across platform. Those underlying peer classes and JNI codes are different. )
另外,提到了finalizer chaining。
子类构造器会自动调用父类构造器,于是可能会想象子类finalizer自动调用父类finalizer。
如果子类复写了父类的finalizer,子类必须手动调用父类的finalier。
Java - 避免使用finalizer的更多相关文章
- Effective Java 第三版——8. 避免使用Finalizer和Cleaner机制
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Java的Finalizer引发的内存溢出
本文介绍的是Java里一个内建的概念,Finalizer.你可能对它对数家珍,但也可能从未听闻过,这得看你有没有花时间完整地看过一遍java.lang.Object类了.在java.lang.Obje ...
- 【java】jstack
介绍 jstack用于打印出给定的java进程ID或core file或远程调试服务的Java堆栈信息,如果是在64位机器上,需要指定选项"-J-d64",Windows的jsta ...
- Could not load java.net.BindException错误解决
出现了错误异常:信息: Illegal access: this web application instance has been stopped already. Could not load ...
- java jvm常用命令工具
[尊重原创文章出自:http://www.chepoo.com/java-jvm-command-tools.html] 一.概述 程序运行中经常会遇到各种问题,定位问题时通常需要综合各种信息,如系统 ...
- java 堆栈分析
再次,研究了一个下午的jhat好jmap.从一开始惊呆.懵懂于那样大量而无聊乏味的数据,到现在有那么一点点收货.赶紧记录下来.没办法,悟性太低... C:\Users\Administrator> ...
- java 锁!
问题:如何实现死锁. 关键: 1 两个线程ta.tb 2 两个对象a.b 3 ta拥有a的锁,同时在这个锁定的过程中,需要b的锁:tb拥有b的锁,同时在这个锁定的过程中,需要a的锁: 关键的实现难点是 ...
- Java多线程之Runable与Thread
Java多线程是Java开发中的基础内容,但是涉及到高并发就有很深的研究可做了. 最近看了下<Java并发实战>,发先有些地方,虽然可以理解,但是自己在应用中很难下手. 所以还是先回顾一下 ...
- Java调试
线上load高的问题排查步骤是: 先用top找到耗资源的进程 ps+grep找到对应的java进程/线程 jstack分析哪些线程阻塞了,阻塞在哪里 jstat看看FullGC频率 jmap看看有没有 ...
随机推荐
- fdisk 磁盘分区
.[root@test4 ~]# fdisk /dev/sda //对sda磁盘进行分区 Device contains neither a valid DOS partition table, no ...
- [转] Linux 硬件设备查看命令
linux查看设备命令 系统 # uname -a # 查看内核/操作系统/CPU信息 # head -n 1 /etc/issue # 查看操作系统版本 # cat /proc/cpuinfo # ...
- Tomcat入门级小白教程
Tomcat 类似与一个apache的扩展型,属于apache软件基金会的核心项目,属于开源的轻量级Web应用服务器,是开发和调试JSP程序的首选,主要针对Jave语言开发的网页代码进行解析,Tomc ...
- 关闭tensorflow运行时的警告信息
执行简单的矩阵相乘的程序: import tensorflow as tf m1 = tf.constant([[3,3]]) m2 = tf.constant([[2],[3]]) product ...
- Oracle 第三方管理工具整理
Oracle 第三方管理工具整理 1.OB(SI Object Browser) 官方网址: http://www.ctdw.com.cn说明:小软件大功能,个人最爱它的数据库导入.导出功能,一键导入 ...
- SQL语句之数据库操作
SQL语句系列 1.SQL语句之行操作 2.SQL语句之表操作 3.SQL语句之数据库操作 4.SQL语句之用户管理 占坑,带写……
- oracle 行列转换函数之WM_CONCAT和LISTAGG的使用(一)
一.wm_concat函数 wm_concat能够实现同样的功能,但是有时在11g中使用需要用to_char()进行转换,否则会出现不兼容现象(WMSYS.WM_CONCAT: 依赖WMSYS 用户, ...
- 解决视图状态消息验证代码 (MAC) 错误
https://blog.csdn.net/bingtingabc/article/details/49148745 2015年10月15日 10:05:56 bingtingabc 阅读数:3397 ...
- @Transcational特性
捕获RuntimeException 捕获Error 并不捕获Checked Exception 在方法中使用@Transcational注解时候,通过throw new Exception(),在发 ...
- 读取P12格式证书的密钥
不想存储p12证书内容,只想存储证书密钥,可通过以下实现读取证书的密钥出来: package com.zat.ucop.service.util; import org.apache.commons. ...