终结 finalize()和垃圾回收(garbage collection)
1、为什么要有finalize()方法?
假定你的对象(并非使用new)获得了一块“特殊”的内存区域,由于垃圾回收器只知道释放那些经由new分配的内存,所以他不知道该如何释放该对象的这块“特殊”内存,为了应对这种情况,java 允许在类中定义一个finalize()的方法。
protected void finalize(){
}
2、finalize()方法在何时调用?
一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用其finalize()方法,并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。
3、finalize()的局限性?
- 对象可能不被回收。
- 垃圾回收并不等于“析构”。
- 垃圾回收值与内存有关。
对于与垃圾回收有关的任何行为来说(尤其是finalize()方法),他们也必须与内存及其回收有关,所以在finalize()方法内做普通的清除工作是不合适的。
那么在finalize()中释放对象是否正确呢?不!如果JVM 并未面临内存耗尽的情形,它是不会浪费时间在回收垃圾上的。即使,JVM进行了垃圾回收, 也无法确切地保证垃圾回收器何时调用该方法,也无法保证调用不同对象的方法的顺序。即使一个对象包含另一个对象的引用,或者在释放一个对象很久以前就释放了另一个对象,也可能会以任意的顺序调用这两个对象的Finalize方法。如果必须保证采用特定的顺序,则必须提供自己的特有清理方法。
4、finalize()用途?
既然finalize()这么废,好像什么都不了,那么到底用它来干嘛呢?
当“使用本地方法”分配内存,例如使用malloc()分配存储空间,除非调用free()否则内存空间将得不到
释放,从而内存泄露。因此free方法就应该在finalize()中用本地方法调用它。
要是对象代表一个打开的文件,在对象被回收前程序员应该关闭这个文件。再要对象中存在没有被适当清除的部分,你的程序就存在很隐晦的错误,finalize()的价值就是用来最终发现这种情况。-------《Thinking in Java》
个人认为,finalize()还是太不可靠,平常还是少用的好。
如果一定要进行回收动作,最好自己写一个回收方法dispose()方法。应当注意的是如果子类重写了父类的dispose()方法,当进行清除动作时,应该先清除子类的,再清除父类的,原因在于:可能子类存在对父类的方法调用。
5、垃圾回收器如何工作?
在某些Java虚拟机中,堆的实现方式就像一个传送带,你每分配一个新对象,它就往前移动一格,这意味着对象存储空间的分配速度非常快。但是,堆的工作又不完全像传送带一样,想象一下,要是堆指针不断向前,势必会导致频繁的内存调度,并最终耗尽资源。其中的秘密在于垃圾回收器的介入。当它工作时,将一面回收空间,一面使堆中的对象紧凑排列,这样“堆指针”就可以很容易移动到更靠近传送带的开始处,也就尽量避免了页面错误。
垃圾回收器模式之引用计数(reference counting):是一种简单但速度很慢的垃圾回收技术。每个对象都含有一个引用计数器,当有引用连接至对象时,引用计数加1。当引用离开作用域或被置为null时,引用计数器减1。垃圾回收器会在含有全部对象的列表上,当发现某个对象的引用技术为0时,就释放其占有的空间。这种模式有种缺陷,如果对象之间存在循环引用,可能会出现“对象应该被回收,但引用计数却不为0的情况”
垃圾回收器模式之停止-复制(stop-and-copy):这种垃圾回收基于一种更快的寻找“活”的对象的方法,并能有效爱的解决对象之间的循环利用。这种方式是:遍历所有对象的引用,这个引用可能会穿过数个对象层次,并最终追溯到其存活在堆栈或静态存储区之中的引用,如果对象之间存在循环利用的话,遍历追溯到最后会发现寻找的是本身的对象,因此这些对象根本不会被发现。而stop-and-copy方式意味着先暂停程序的运行,然后将所有存活的对象从当前堆复制到另外一个堆,没有被复制的全部都是垃圾,当对象被复制到新堆时,他们是一个挨着一个的。所以新堆保持紧凑排列。值得注意的是,大型对象占有自己的内存块,copy时不进行复制,如果该对象被引用就把该内存块的代数加1来表示被引用到了。
垃圾回收器模式之标记-清扫(mark-and-sweep): stop-and-copy存在两个问题:一、你得有两个堆,然后你得在这两个分离的堆之间来回倒腾,从而维护比实际需要多一倍的空间。某些Java虚拟机对此问题的处理方式是,按需从堆中分配几块较大的内存,复制动作发生在这些大块内存之间。二、如果稳定的程序只产生少量的垃圾,复制动作岂不是很浪费?为此引出了mark-and-sweep模式,当它遍历所有的引用,进而找出所有存活的对象,每当它找到一个存活对象,就会给对象一个标记,这个过程不会回收任何对象。只有在标记工作完成后,没被标记的对象被垃圾回收器回收。剩下的空间的不连续的,垃圾回收器要是希望得到连续空间的话,就得重新整理剩下的对象。对一般用途而言,mark-and-sweep 方式速度相当慢,但是用在处理少量垃圾或不产生垃圾时,它的速度就很快了。mark-and-sweep 工作也必须在程序暂停的情况下工作。
垃圾回收器采用的 自适应 的技术,按照需求在各个模式之间切换,当JVM监视到所有对象都很稳定,只产生了少量的垃圾,就自动采用mark-and-sweep模式,要是堆空间出现很多碎片,就会切换回 stop-and-copy方式。
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Android仿QQ好友详情页下拉顶部图片缩放效果
- 数组对象转为Map
- TensorFlow2.X使用图片制作简单的数据集训练模型
- Android高性能日志写入方案的实现
- MySQL 三万字精华总结 + 面试100 问,吊打面试官绰绰有余(收藏系列)
- 想后台运行没想到导致磁盘满了
- 来看一道"简单的"C语言面试题
- 这行代码的打印结果确实让人迷惑!
- 如何实现一个高效的启发式算法?(VRPTW篇)
- Ubuntu Server搭建Hyperledger Fabric 2.1学习环境
- 辛辛苦苦学会的 webpack dll 配置,可能已经过时了
- 【程序中的数学】利用德摩根定律简化布尔运算
- Conjob For hybris
- ListView通用泛型适配器
- Android实现C/S聊天室