Java中一次对象的自我拯救探究
2017-05-25 21:02
267 查看
《深入理解java虚拟机》第二版 67页,一次对象自我拯救这个例子很不错,在这里分享出来。
并且从源码角度进行分析。
代码如下:
/**
* 1 对象可以在被GC时自我拯救
* 2 这种自救机会只有一次,因为一个对象的finalize()方法最多只会被系统自动调用一次
* Created by 明明如月 on 2017-05-24.
*/
public class FinalizeEscapeGC {
private static FinalizeEscapeGC SAVE_HOOK = null;
private void isAlive(){
System.out.println("yes, i am still alive :)");
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("finalize method executed!");
FinalizeEscapeGC.SAVE_HOOK = this;
}
public static void main(String[] args) throws InterruptedException {
SAVE_HOOK = new FinalizeEscapeGC();
//对象第一次拯救自己
SAVE_HOOK = null;
System.gc();
//因为finalize 方法优先级很低,所以暂停0.5秒等待它
Thread.sleep(500);
if(SAVE_HOOK != null){
SAVE_HOOK.isAlive();
}else{
System.out.println("no, i am dead :(");
}
//----------下面代码完全相同但是自救失败---------
//对象第一次拯救自己
SAVE_HOOK = null;
System.gc();
//因为finalize 方法优先级很低,所以暂停0.5秒等待它
Thread.sleep(500);
if(SAVE_HOOK != null){
SAVE_HOOK.isAlive();
}else{
System.out.println("no, i am dead :(");
}
}
}
运行结果
我们可以看出,SAVE_HOOK对象的finalize()方法确实被GC回收器出发过,并且在被收集前成功逃脱。
我们先研究一下垃圾回收方法
此方法调用垃圾回收器,回收被遗弃的对象。并且和Runtime.getRuntime().gc()这个方法等价,因为从源码中我们看出其实就是直接调用了那个方法。
我们看到这个是原生的方法,哪怕gc方法没有被显式调用,虚拟机根据需要自动执行垃圾回收线程。
我们再看看Object对象的finalize()方法:
主要几点:
当垃圾回收器断定一个对象不再被引用,该对象的该方法就会被垃圾回收器调用。
子类可以重写finalize方法来释放系统资源或者执行一些清理的操作。
finalize方法可以执行任何操作,包括再使得该对象可用(拯救该对象)。
Java编程语言并不保证哪一个线程来调用某个对象的finalize方法。
finalize方法只会被Java虚拟机调用一次。
主方法中,上半段和下半段代码相同,可是一次逃脱成功,一次逃脱失败,是因为任何一个对象的finalize()方法只会被系统自动调用一次,如果对象再次面临回收,他的finalize()方法不会再次被执行,第二段代码的自救行动就失败了(因为再次调用gc来执行垃圾回收,该对象的finalize方法不会再次被执行)。
书中作者不鼓励使用该方法来拯救对象。
作者表示有的教材鼓励采用这种方式在finalize()方法中“关闭外部资源”之类的工作。finalize()能做的工作通过try-finally或者其他方式也可以做得更好、更及时,所以请淡忘这个方法。
这一点和Java源码中的解释有点冲突,仅供参考,读者自己取舍就好。
大家在编程过程中,尤其在学习虚拟机的一些知识时,多去查看源码
并且从源码角度进行分析。
代码如下:
/**
* 1 对象可以在被GC时自我拯救
* 2 这种自救机会只有一次,因为一个对象的finalize()方法最多只会被系统自动调用一次
* Created by 明明如月 on 2017-05-24.
*/
public class FinalizeEscapeGC {
private static FinalizeEscapeGC SAVE_HOOK = null;
private void isAlive(){
System.out.println("yes, i am still alive :)");
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("finalize method executed!");
FinalizeEscapeGC.SAVE_HOOK = this;
}
public static void main(String[] args) throws InterruptedException {
SAVE_HOOK = new FinalizeEscapeGC();
//对象第一次拯救自己
SAVE_HOOK = null;
System.gc();
//因为finalize 方法优先级很低,所以暂停0.5秒等待它
Thread.sleep(500);
if(SAVE_HOOK != null){
SAVE_HOOK.isAlive();
}else{
System.out.println("no, i am dead :(");
}
//----------下面代码完全相同但是自救失败---------
//对象第一次拯救自己
SAVE_HOOK = null;
System.gc();
//因为finalize 方法优先级很低,所以暂停0.5秒等待它
Thread.sleep(500);
if(SAVE_HOOK != null){
SAVE_HOOK.isAlive();
}else{
System.out.println("no, i am dead :(");
}
}
}
运行结果
我们可以看出,SAVE_HOOK对象的finalize()方法确实被GC回收器出发过,并且在被收集前成功逃脱。
我们先研究一下垃圾回收方法
此方法调用垃圾回收器,回收被遗弃的对象。并且和Runtime.getRuntime().gc()这个方法等价,因为从源码中我们看出其实就是直接调用了那个方法。
我们看到这个是原生的方法,哪怕gc方法没有被显式调用,虚拟机根据需要自动执行垃圾回收线程。
我们再看看Object对象的finalize()方法:
主要几点:
当垃圾回收器断定一个对象不再被引用,该对象的该方法就会被垃圾回收器调用。
子类可以重写finalize方法来释放系统资源或者执行一些清理的操作。
finalize方法可以执行任何操作,包括再使得该对象可用(拯救该对象)。
Java编程语言并不保证哪一个线程来调用某个对象的finalize方法。
finalize方法只会被Java虚拟机调用一次。
主方法中,上半段和下半段代码相同,可是一次逃脱成功,一次逃脱失败,是因为任何一个对象的finalize()方法只会被系统自动调用一次,如果对象再次面临回收,他的finalize()方法不会再次被执行,第二段代码的自救行动就失败了(因为再次调用gc来执行垃圾回收,该对象的finalize方法不会再次被执行)。
书中作者不鼓励使用该方法来拯救对象。
作者表示有的教材鼓励采用这种方式在finalize()方法中“关闭外部资源”之类的工作。finalize()能做的工作通过try-finally或者其他方式也可以做得更好、更及时,所以请淡忘这个方法。
这一点和Java源码中的解释有点冲突,仅供参考,读者自己取舍就好。
大家在编程过程中,尤其在学习虚拟机的一些知识时,多去查看源码
相关文章推荐
- [Java拾遗]Java对象大小探究
- 静态代码扫描中Java资源对象关闭的探究
- Java拾遗]Java对象大小探究
- 垃圾回收:没在GC Root链上的对象通过finalize()自我拯救的过程
- 【javaweb:session】session域对象中保存的数据在什么范围内有效?一次会话!!
- 让Java类一次只能声明一个对象
- 关于Android开发中Java对象序列化的一次测试
- Java 工具类(泛型:仅一次调用返回多个对象)
- 记录一次大对象导致的Java堆内存溢出问题
- Java IO中的对象流之一次读入多个对象
- Java多线程探究-Lock锁对象
- 如何计算java对象占用的内存
- C#能否象JAVA那样根据类名建立Class类型的对象
- 将java的对象序列化成文件,并从文件中反序列化。
- java对象转为java String的几种常用方法剖析
- Java对象的初始化过程[原]
- java对象序列化学习笔记
- java对象转为java String的几种常用方法剖析
- Java对象序列化(整理篇)
- 使用 Hibernate 将 Java 对象持久保存到 IBM DB2 通用数据库中