Thinking in Java阅读笔记(二)
2014-11-07 16:40
155 查看
第四章 初始化和清理
清理(Cleanup):终结(finalization)与垃圾回收(garbage collection)
Java 提供了垃圾回收器来回收那些不再被使用的对象的内存空间,但是请你想想某些不同寻常的情况。假设你的对象并非经由new获得某种“特殊”内存。
垃圾回收器只知道释放那些经由new分配得来的内存,因此它不知道如何释放你这个对象所占的“特殊”内存。为了应对这种情况,Java提供了一个finalize()函数,你可以为自己的class定义此一函数。
当垃圾回收器打算开始释放你的对象所占用的存储空间时,会先调用其finalize(),并且在下一次垃圾回收动作发生时才回收该对象所占的内存。所以,如果你使用finalize(),它便让你得以在“垃圾回收时刻”执行某些重要的(你自己的)清理动作。
你的对象可能不会被回收
你可能发现,某个对象所占用的空间永远没有被释放掉,因为你的程序可能永远不会逼近内存用完的那一刻。如果你的程序执行完毕,而垃圾回收器完全没有被启动以释放你的对象所占据的内存,那些空间便会在程序终止时才一次归还给操作系统。这是好事,因为垃圾回收器会带来额外负担,如果永远不启动它,就永远不需要付出额外代价。
finalize()存在是为了什么?
垃圾回收动作(garbage collection)只回收内存 也就是说,垃圾回收器存在的唯一理由,就是要回收那些在你程序中再也用不着的内存空间。所以任何和垃圾回收动作捆绑在一起的行为,也都只能和内存或内存的释放相关。这是否意味着如果你的对象内含其他对象,在finalize()中应该明确释放那些对象?答案是no,垃圾回收器所留意的是“对象内存”的释放,不论对象被生成的方式究竟为何。如此一来,对finalize()的需求便局限于特定情况之下。这个情况就是:当你的对象以”对象生成“之外的方式分配了某种存储空间。那么究竟怎样才会碰到上述情况?似乎只有在你通过Java的非政策管道来分配内存,打算做一些类似C会做的事情时,才是使用
4000
finalize()的适当时机。这种情况主要发生在采用原生函数时,那是一种在Java程序中调用non-Java程序代码的方法。在non-Java程序代码中,C的malloc()函数族系可能会被调用,用以分配存储空间,而且除非你调用free(),否则其占用空间永远不会被释放,进而产生内存漏洞(memory
leak)。当然啦,free()是C/C++函数,所以你得在finalize()中以原生函数加以调用。
阅读至此,你或许明白,你不应该过度使用finalize()。它并不是摆放正常清理动作的合适地点。
如果System.gc()被唤起,终结动作便会发生于所有对象身上。不论System.runFinalization()是否被唤起,似乎都没有任何差别。
死亡条件(The death condition)
一般情况下,你的程序不能依靠“finalize()被调用”才能正常运作。finalize()函数还有一个很有意思的用途,那就是对象的“死亡条件”检查。当你对某个对象不再感兴趣——也就是它可以被清理时——这个对象应该处于某种状态,使它所占用的内存空间得以被安全释放。
清理(Cleanup):终结(finalization)与垃圾回收(garbage collection)
Java 提供了垃圾回收器来回收那些不再被使用的对象的内存空间,但是请你想想某些不同寻常的情况。假设你的对象并非经由new获得某种“特殊”内存。
垃圾回收器只知道释放那些经由new分配得来的内存,因此它不知道如何释放你这个对象所占的“特殊”内存。为了应对这种情况,Java提供了一个finalize()函数,你可以为自己的class定义此一函数。
当垃圾回收器打算开始释放你的对象所占用的存储空间时,会先调用其finalize(),并且在下一次垃圾回收动作发生时才回收该对象所占的内存。所以,如果你使用finalize(),它便让你得以在“垃圾回收时刻”执行某些重要的(你自己的)清理动作。
你的对象可能不会被回收
你可能发现,某个对象所占用的空间永远没有被释放掉,因为你的程序可能永远不会逼近内存用完的那一刻。如果你的程序执行完毕,而垃圾回收器完全没有被启动以释放你的对象所占据的内存,那些空间便会在程序终止时才一次归还给操作系统。这是好事,因为垃圾回收器会带来额外负担,如果永远不启动它,就永远不需要付出额外代价。
finalize()存在是为了什么?
垃圾回收动作(garbage collection)只回收内存 也就是说,垃圾回收器存在的唯一理由,就是要回收那些在你程序中再也用不着的内存空间。所以任何和垃圾回收动作捆绑在一起的行为,也都只能和内存或内存的释放相关。这是否意味着如果你的对象内含其他对象,在finalize()中应该明确释放那些对象?答案是no,垃圾回收器所留意的是“对象内存”的释放,不论对象被生成的方式究竟为何。如此一来,对finalize()的需求便局限于特定情况之下。这个情况就是:当你的对象以”对象生成“之外的方式分配了某种存储空间。那么究竟怎样才会碰到上述情况?似乎只有在你通过Java的非政策管道来分配内存,打算做一些类似C会做的事情时,才是使用
4000
finalize()的适当时机。这种情况主要发生在采用原生函数时,那是一种在Java程序中调用non-Java程序代码的方法。在non-Java程序代码中,C的malloc()函数族系可能会被调用,用以分配存储空间,而且除非你调用free(),否则其占用空间永远不会被释放,进而产生内存漏洞(memory
leak)。当然啦,free()是C/C++函数,所以你得在finalize()中以原生函数加以调用。
阅读至此,你或许明白,你不应该过度使用finalize()。它并不是摆放正常清理动作的合适地点。
如果System.gc()被唤起,终结动作便会发生于所有对象身上。不论System.runFinalization()是否被唤起,似乎都没有任何差别。
死亡条件(The death condition)
一般情况下,你的程序不能依靠“finalize()被调用”才能正常运作。finalize()函数还有一个很有意思的用途,那就是对象的“死亡条件”检查。当你对某个对象不再感兴趣——也就是它可以被清理时——这个对象应该处于某种状态,使它所占用的内存空间得以被安全释放。
class Book{ boolean checkedOut = false; Book(boolean checkedOut){ this.checkedOut = checkedOut; } void checkIn(){ this.checkedOut = false; } public void finalize(){ if(checkedOut){ System.out.println("Error:checked out"); } } } public class DeathCondition { public static void main(String[] args) { Book novel = new Book(true); //Proper cleanup novel.checkIn(); //Drop the reference,forget to clean up new Book(true); //Force garbage collection & finalization System.gc(); } }在这个例子中,死亡条件是“所有Book对象都被预期在它们被回收之前先被登录(checked in)”。但在main()中,由于程序员的错误,有一本书未被登录。如果没有finalize()来检查死亡条件,这会是一只棘手的臭虫。请记住,System.gc()被用来强迫终结动作的发生(你应该在程序开发过程中进行此事,以便协助侦错)。
相关文章推荐
- Thinking in Java阅读笔记(二)
- thinking in java 阅读笔记 第一章 对象入门
- thinking in java 阅读笔记 第一章 对象入门
- thinking in java 阅读笔记 第二章 一切都是对象
- thinking in java 阅读笔记 第二章 一切都是对象
- thinking in java 阅读笔记 第一章 对象入门
- thinking in java 阅读笔记 第一章 对象入门
- thinking in java 阅读笔记 第一章 对象入门
- thinking in java 阅读笔记 第一章 对象入门
- thinking in java 阅读笔记 第二章 一切都是对象
- thinking in java 阅读笔记 第一章 对象入门
- thinking in java 阅读笔记 第一章 对象入门
- thinking in java 阅读笔记 第一章 对象入门
- thinking in java 阅读笔记 第一章 对象入门
- 2014.06.21 Thinking in java 阅读笔记
- thinking in java 阅读笔记 第一章 对象入门
- thinking in java 阅读笔记 第一章 对象入门
- thinking in java 阅读笔记 第一章 对象入门
- thinking in java 阅读笔记 第二章 一切都是对象
- thinking in java 阅读笔记 第一章 对象入门