java垃圾回收期如何工作(编程思想)

垃圾回收器如何工作:
在以前的程序语言中,在堆上分配对象的代价十分昂贵,因此读者会自然觉得对Java中所有对象(基本类型除外)都在堆上分配的方式也非常高昂。然而,垃圾回收期对提高对象的创建速度,却具有明显的效果。
打个比方,你可以吧C++里面的堆想象成一个院子,里面的每个对象都负责管理自己的地盘。一段时间之后,对象可能被销毁,但地盘必须加以重用。在某些Java虚拟机中,堆的实现截然不同:它更像一个传送带,每分配一个对象,它就往前移动一格。这意味着对象存储空间的分配速度非常快。Java的“堆指针”只是简单地移动到尚未分配的区域,其效率比得上C++在堆栈上分配空间的效率。
java中的堆并非完全像传送带那样工作。要是真的那样的恶化,势必会导致频繁的内存页面调度————将其移进移出硬盘,因此会显得需要拥有比实际需要更多的内存。页面调度会显著地影响性能,最终,在创建了足够多的翠香之后,内存资源将耗尽。其中的秘密在于垃圾回收器的介入。当它工作时,将一面回收空间,一面使堆中的对象紧凑排列,这样“堆”指针就可以很容易移动到更靠近传送带的开始处,也就避免了页面错误。通过垃圾回收器对对象重新排序,实现了一种高速的、有无限空间可供分配的堆模型。
想要更好地理解Java中的垃圾回收,可以了解一下其他系统中的垃圾回收机制。引用计数器是一种简单但速度很慢的垃圾回收技术。每个对象都含有一个引用计数器,让有引用连接至对象时,引用技术加1.当对象离开作用域或被置为null时,引用计数器减少。虽然管理引用技术的开销不大,但这项开销在整个程序生命周期中持续发生。垃圾回收期会在含有全部对象的列表上遍历,当发现某个对象的引用计数为0时,就释放其占用的空间(但是,引用计数模式经常会在计数值变成0时立即释放对象)。这种方法有个缺陷,如果对象之间存在循环引用,可能出现“对象应该被回收,但引用计数却不为零”的情况。对于垃圾回收器而言,定位这样的交互自引用的对象组所需的工作量极大。引用计数常用来说明垃圾收集的工作方式,但似乎从未被应用于任何一种Java虚拟机实现中。
在一些更快的模式中,垃圾回收期并非基于引用计数技术。它们依据的思想是:对任何“活”的对象,一定能最终追溯到其存货在堆栈或静态存储区之中的引用。这个引用链条可能会穿过数个对象层次。由此,如果从堆栈和静态存储区开始,遍历所有的引用,就能找到所有“活"的对象。对于发现的每个引用,必须追踪它锁引用的对象,然后是此对象包含的而所有引用,如此反复进行,知道“根源于堆栈和静态存储区的引用”形成的网络全部被访问为止。你所访问过的对象必须都是“活”的。注意,这就解决了“交互自引用的对象组”的问题————这种现象根本不会被发现,因此也就被自动回收了。
在这种方式下,Java虚拟机将采用一种自适应的垃圾回收技术。置于如何找到的存活对象,取决于不同的java虚拟机实现。有一种做法名为停止——赋值(stop and copy)。显然意味着,先暂停程序的运行(所以它不属于后台回收模式),然后将所有存活的对象从当前堆赋值到另一个堆,没有被赋值的全部都是垃圾,当对象被赋值到新堆时,它们是一个挨着一个的,所以新堆保持紧凑排列,然后就可以按前述方法简单、直接地分配新空间了。
当把对象从一处搬到另一处时,所有指向它的那些引用都必须修正。位于堆或者静态存储区的引用可以直接被修正,但可能还有其他指向这些对象的引用,它们在遍历的过程中才能被找到(可以想象成有个表格,讲话旧地址映射至新地址)
对于这种所谓的复制式回收器而言,效率会降低,这有两个原因。首先,得有两个堆,然后得在这两个分离的堆之间来回捣腾,从而得维护比实际需要多1倍的空间。某些Java虚拟机对此问题的处理方式是,按需从堆中分配几块较大的内存,复制动作发生在这些大块内存之间。
第二个问题在于复制。程序进入稳定状态之后,可能只会产生少量垃圾,甚至没有垃圾,尽管如此,复制式回收器仍然会将所有内存自一处复制到另一处,这很浪费。为了避免这种情形,一些java虚拟机会进行检查:要是没有新垃圾产生,就会转换到另一种工作模式(即“自适应”)。对一般用途而言,“标记——清扫”方式速度相当慢,但是当你知道只会产生少量垃圾甚至不会产生垃圾时,它的速度就很快了。
“标记——清扫”锁依据的思路同样是从堆栈和静态存储区出发,遍历所有的引用,从而找出所有存活的对象。每当它找到一个存活对象,就会给对象设一个标记,这个过程中不会回收任何对象。只有全部标记工作完成时,清理工作才会开始。在清理过程中,没有标记的对象将被释放,不会发生任何复制操作。所以剩下的堆空间是不连续的,垃圾回收器要是希望得到连续空间的话,就得重新整理剩下的对象。
“停止——复制”的意思是这种垃圾回收动作不是在后台进行的;相反,垃圾回收器动作发生的同事,程序将会被暂停。在Sun公司的文档中会发现,许多参考文档将垃圾回收视为低优先级的后台进程,但实际上垃圾回收器在Sun公司早期版本的java虚拟机中并非以这种方式实现的。当可用内存数量较低的时,Sun版本的垃圾回收器会暂停运行程序,同样,“标记-清扫”工作也必须在程序暂停的情况下才能进行。
如上文所述,在这里所讨论的Java虚拟机中,内存分配以较大的“块”为单位。如果对象较大,它会占用单独的块。严格来说,“停止-复制”要求在释放旧有对象之前,必须先把所有的存货兑现从旧堆复制到新堆,这将导致大量内存复制行为。有了快之后,垃圾回收期在回收的时候就可以往飞起的块里拷贝对象了。每个块都用相应的代数(generation count)来记录它是否存活。通常,如果快被某处引用,其代数会增加,垃圾回收期会定期进行完整的清理动作————大型对象仍然不会被复制(只是其代数会增加),内含小型对象的那些块则被复制并整理。java虚拟机会进行监视,如果所有对象都很稳定,垃圾回收器的效率降低的话,就切换到“标记-清扫”方式;同样,java虚拟机会跟踪“标记-清扫”的效果,要是堆空间出现很多碎片,就会切换回“停止-复制”的方式。这就是“自适应”技术,你可以给它个啰嗦的称呼:“自适应的、分代的、停止-复制、标记-清扫”式垃圾回收器。

时间: 2024-08-04 10:15:15

java垃圾回收期如何工作(编程思想)的相关文章

JAVA垃圾回收分代处理思想

原文链接:http://www.cnblogs.com/laoyangHJ/archive/2011/08/17/JVM.html JVM分代垃圾回收策略的基础概念 JVM分代垃圾回收策略的基础概念 由于不同对象的生命周期不一样,因此在JVM的垃圾回收策略中有分代这一策略.本文介绍了分代策略的目标,如何分代,以及垃圾回收的触发因素. 文章总结了JVM垃圾回收策略为什么要分代,如何分代,以及垃圾回收的触发因素. 为什么要分代 分代的垃圾回收策略,是基于这样一个事实:不同的对象的生命周期是不一样的.

java垃圾回收器的工作原理

Java 语言的一大特点就是可以进行自动垃圾回收处理,而无需开发人员过于关注系统资源,例如内存资源的释放情况.自动垃圾收集虽然大大减轻了开发人员的工作量,但是也增加了软件系统的负担. 拥有垃圾收集器可以说是 Java 语言与 C++语言的一项显著区别.在 C++语言中,程序员必须小心谨慎地处理每一项内存分配,且内存使用完后必须手工释放曾经占用的内存空间.当内存释放不够完全时,即存在分配但永不释放的内存块,就会引起内存泄漏,严重时甚至导致程序瘫痪. 以下列举了垃圾回收器常用的算法及实验原理: 引用

总结Java垃圾回收器的方法和原理

1. 垃圾回收只与内存有关 在Java中,我们new完对象之后,垃圾回收器负责回收无用的对象占据的内存资源.这与C++不同,在C++中,准许使用局部对象,回收对象时候,需要用到finalize()析构函数.C++的对象创建在堆栈中,而Java对象创建在堆中,所以我们创建完对象之后,Java的垃圾回收器在堆中,会自动帮我们回收垃圾,至于何时回收垃圾,我们不得而知了. 2.垃圾回收用到的方法 (1)finalize() 该方法是用来回收“特殊”的内存,而这内存不是new出来的,所以垃圾回收器无法回收

Java垃圾回收介绍(译)

在Java中,对象内存空间的分配与回收是由JVM中的垃圾回收进程自动完成的.与C语言不同的是,在Java中开发者不需要专门为垃圾回收写代码.这是使Java流行的众多特征之一,也帮助了程序员写出了更好的Java应用. 这是一个四部分的系列教程,以了解在Java中垃圾回收的基础, Java垃圾回收介绍 Java垃圾回收如何工作? Java垃圾回收器的类型 监控和分析Java垃圾回收 这篇教程是系列中的第一部分.本篇中会解释一些基本术语,像JDK,JVM,JRE,HotSpot VM,然后去理解JVM

77.JAVA编程思想——模拟垃圾回收

77.JAVA编程思想--模拟垃圾回收 这个问题的本质是若将垃圾丢进单个垃圾筒,事实上是未经分类的.但在以后,某些特殊的信息必须恢复,以便对垃圾正确地归类.在最开始的解决方案中,RTTI 扮演了关键的角色.这并不是一种普通的设计,因为它增加了一个新的限制.正是这个限制使问题变得非常有趣--它更象我们在工作中碰到的那些非常麻烦的问题.这个额外的限制是:垃圾抵达垃圾回收站时,它们全都是混合在一起的.程序必须为那些垃圾的分类定出一个模型.这正是RTTI 发挥作用的地方:我们有大量不知名的垃圾,程序将正

Java编程思想之二十 并发

20.1 并发得多面性 并发编程令人困惑的一个主要原因:使用并发时需要解决的问题有多个,而实现并发的方法也有多种,并且在这两者之间没有明显的映射关系. 20.1.1 更快的执行 速度问题初听起来很简单:如果你需要一个程序运行得更快,那么可以将起断开为多个片段,在单个处理器上运行每个片段. 并发通常是提高运行在单个处理器上的程序的性能,但在单个处理器上运行的并发程序开销确实应该比该程序所有部分都顺序执行开销大,因为其中增加了所谓的上下文切换的代价. 如果没有任务会阻塞,那么在单处理器上使用并发就没

《Java编程思想(第4版)》pdf

下载地址:网盘下载 内容简介 编辑 本书赢得了全球程序员的广泛赞誉,即使是最晦涩的概念,在Bruce Eckel的文字亲和力和小而直接的编程示例面前也会化解于无形.从Java的基础语法到最高级特性(深入的面向对象概念.多线程.自动项目构建.单元测试和调试等),本书都能逐步指导你轻松掌握.[1] 从本书获得的各项大奖以及来自世界各地的读者评论中,不难看出这是一本经典之作.本书的作者拥有多年教学经验,对C.C++以及Java语言都有独到.深入的见解,以通俗易懂及小而直接的示例解释了一个个晦涩抽象的概

《java编程思想》有必要买吗

<java编程思想>有必要买吗 1.看到过好多个这样的提问,其实我一般真的不那么容易分享自己的这点心得的,这是第一次回答这样的"推荐书籍"方面的问题. 我买编程方面的书籍,有一个非常清晰.坚决的原则--电子工业出版社的! 对于JAVA,建议你看如下的书: 首先,<21天学通JAVA>: 然后,<30天学通JAVA项目案例开发>(这本书的内容都是实例的,非常棒的实例!适合初学者的同时,又有实际应用性!) 以上的书籍,是基于你只想学J2SE的. 我还建议

Java 编程思想 第五章 ----初始化与清理(1)

从今天开始每天一小时的java 编程思想的阅读和编码,其实就是把书上的代码抄下来. 5.5 清理:终结处理和垃圾回收 初始化和清理工作同等重要,但是清理工作却被常常忘记,但是在使用对象之后,对对象弃之不顾的做法并不是很安全.Java有自己的垃圾回收器负责回收无用的对象占据的内存资源.但也有特殊情况:假定你的内存区域不是用new获得的,这是无法用垃圾回收器释放所以java中允许在类中定义一个名为 finalize()的方法.       工作原理: 一旦垃圾回收器准备好释放对象占用的存储空间,将首