码迷,mamicode.com
首页 > 编程语言 > 详细

第5章(2) Java的垃圾回收器

时间:2015-11-24 06:20:54      阅读:203      评论:0      收藏:0      [点我收藏+]

标签:

终结处理

Java有垃圾回收器回收无用对象占据的内存资源。但垃圾回收器只知道释放经由new分配的内存,如果用其他的方法获得了一块“特殊”的内存区域,就需要我们自己完成清理工作。Java提供了finalize()方法来解决这一问题。

finalize()方法

工作原理:一但垃圾回收器准备好释放对象占用的存储空间,将首先调用其finalize()方法,并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。

其作用,换句话说就是:在你不再需要某个对象之前,如果必须执行某些动作,那么你得自己去做。

例如:假设某个对象在创建的过程中会将自己绘制到屏幕上,如果不是明确的擦除,它可能永远得不到清理,这时我们就需要在finalize()方法中加入擦除的功能。

垃圾回收

我们来探讨垃圾回收器是如何工作的?

常见的垃圾回收机制:

(1). 引用计数(简单但速度很慢)

每个对象都含有一个引用记数器。

当有引用链接至对象时,引用记数加1

当引用离开作用域或被置为null时,引用计数减1.

虽然管理引用记数的开销不大,但这项开销在整个程序生命周期中将持续发生。垃圾回收器会在含有全部对象的列表上遍历,当发现某个对象的引用记数为0时,就释放其占用的空间(但是,引用记数模式经常会在记数值变为0时立即释放对象)

这种方法有个缺陷,如果对象之间存在循环引用,可能会出现“对象应该被回收,但引用计数却不为零”的情况。对垃圾回收器而言,定位这样的交互自引用的对象组所需的工作量极大。引用记数常用来说明垃圾收集的工作方式,但似乎从未被应用于任何一种Java虚拟机实现中。

(2). “追溯引用”

在一些更快的模式中,垃圾回收器并非基于引用记数技术。它们依据的思想是:对任何“活”的对象,一定能最终追溯到其存活在堆栈或静态存储区之中的引用。这个引用链条可能会穿过数个对象层次。

由此,如果从堆栈和静态存储区开始,遍历所有的引用,就能找到所有“活”的对象。对于发现的每个引用,必须追踪它所引用的对象,然后是此对象包含的所有引用,如此反复进行,直到“根源于堆栈和静态存储区的引用”所形成的网络全部被访问为止。您所访问过的对象必须都是“活”的。注意,这就解决了“交互自引用的对象组”的问题——这种现象根本不会被发现,因此也就被自动回收了。

这种思路有下面这两种做法:

(2-1). 停止-复制(stop-and-copy)(垃圾少时效率低,需要空间大)

有一种做法名为停止-复制(stop-and-copy)。显然这意味着,先暂停程序的运行(所以它不属于后台回收模式),然后将所有存活的对象从当前堆复制到另一个堆,没有被复制的全部都是垃圾。(挑拣的工作)当对象被复制到新堆时,它们是一个挨着一个的,所以新堆保持紧凑排列,然后就可以按前述方法简单、直接地分配新空间了。

 当把对象从一处搬到另一处时,所有指向它的那些引用都必须修正。位于堆或静态存储区的引用可以直接被修正,但可能还有其他指向这些对象的引用,它们在遍历的过程中才能被找到(可以想像成有个表格,将旧地址映射至新地址)

对于这种所谓的“复制式回收器”而言,效率会降低,这有两个原因。

首先,得有两个堆,然后得在这两个分离的堆之间来回捣腾,从而维护比实际需要多一倍的空间。某些Java虚拟机对此问题的处理方式是,按需从堆中分配几块较大的内存,复制动作发生在这些大块内存之间。

第二个问题在于复制。程序进入稳定状态之后,可能只会产生少量垃圾,甚至没有垃圾。 

(2-2).标记-清扫(mark-and-sweep)(速度较快,占用空间少,但释放后空间不连续)

 尽管如此,复制式回收器仍然会将所有内存自一处复制到另一处,这很浪费。为了避免这种情形,一些Java虚拟机会进行检查:要是没有新垃圾产生,就会转换到另一种工作模式(即“自适应”)。这种模式称为标记-清扫(mark-and-sweep)Sun公司早期版本的Java虚拟机使用了这种技术。对一般用途而言,“标记-清扫”方式速度相当慢,但是当您知道只会产生少量垃圾甚至不会产生垃圾时,它的速度就很快了。

“标记-清扫”所依据的思路同样是从堆栈和静态存储区出发,遍历所有的引用,进而找出所有存活的对象。每当它找到一个存活对象,就会给对象设一个标记,这个过程中不会回收任何对象。只有全部标记工作完成的时候,清理动作才会开始。在清理过程中,没有标记的对象将被释放,不会发生任何复制动作。所以剩下的堆空间是不连续的,垃圾回收器要是希望得到连续空间的话,就得重新整理剩下的对象。

停止-复制”的意思是这种垃圾回收动作不是在后台进行的;相反,垃圾回收动作发生的同时,程序将会被暂停。在Sun公司的文档中会发现,许多参考文献将垃圾回收视为低优先级的后台进程,但事实上垃圾回收器在Sun公司早期版本的Java虚拟机中并非以这种方式实现的。当可用内存数量较低时,Sun版本的垃圾回收器会暂停运行程序,同样,“标记-清扫”工作也必须在程序暂停的情况下才能进行。

“自适应的、分代的、停止-复制、标记-清扫”式的垃圾回收器

Java虚拟机会进行监视,如果所有对象都很稳定,垃圾回收器的效率降低的话,就切换到“标记-清扫”方式;同样,Java虚拟机会跟踪“标记-清扫”的效果,要是堆空间出现很多碎片,就会切换回“停止-复制”方式。这就是“自适应”技术,您可以给它个罗嗦的称呼:“自适应的、分代的、停止-复制、标记-清扫”式垃圾回收器。

第5章(2) Java的垃圾回收器

标签:

原文地址:http://blog.csdn.net/qq_18738333/article/details/50006323

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!