Java编程思想笔记之垃圾回收器

        Java中所有对象(基本类型除外)都在堆上分配对象,这在其他很多语言中,代价十分高

昂。然而,垃圾回收器对于提高对象的创建速度,却具有明显的效果。存储空间的释放会影响

存储空间的分配,这是某些Java虚拟机的工作方式,Java从堆分配空间的速度,可以和其他语

言从堆栈上分配空间的速度相媲美。

        打个比方,你可以把C++里的堆想像成一个院子,里面每个对象都负责管理自己的地盘,

一段时间以后,对象可能被销毁,但地盘必须加以重用。在某些Java虚拟机中,堆的实现截然

不同:它更像一个传送带,每分配一个新对象,它就往前移动一格。这意味着对象存储空间的

分配速度非常快。 Java的“堆指针”只是简单地移动到尚未分配的区域,其效率比得上C++在堆

栈上分配空间的效率。当然,实际过程中在簿记工作方面还有少量额外开销,但比不上査找可

用空间开销大。

        Java中的堆不可能完全像传送带那样工作。要真是那样的话,势必会导致频繁的内存页面

调度——将其移进移出硬盘,因此会显得需要拥有比实际需要更多的内存。页面调度会显著地

影响性能,最终,在创建了足够多的对象之后,内存资源将耗尽。其中的秘密在于垃圾回收器

的介入。当它工作时,将一面回收空间,一面使堆中的对象紧凑排列,这样“堆指针”就可以很容

易移动到更靠近传送带的开始处,也就尽量避免了页面错误。通过垃圾回收器对对象重新排

列,实现了一种髙速的、有无限空间可供分配的堆模型。

        垃圾回收机制

        引用记数是一种简单但速度很慢的垃圾回收技术。每个对象都含有一个引用记数器,当有

引用连接至对象时,引用计数加1。当引用离开作用域或被置为null时,引用计数减1。虽然管理

引用记数的开销不大,但这项开销在整个程序生命周期中将持续发生。垃圾回收器会在含有全

部对象的列表上遍历,当发现某个对象的引用计数为0时,就释放其占用的空间(但是,引用记

数模式经常会在记数值变为0时立即释放对象)。这种方法有个缺陷,如果对象之间存在循环引

用,可能会出现“对象应该被回收,但引用计数却不为零”的情况。对垃圾回收器而言,定位这样

的交互自引用的对象组所需的工作量极大。引用记数常用来说明垃圾收集的工作方式,但从未

被应用在任何一种Java虚拟机实现中。

        在一些更快的模式中,垃圾回收器并非基于引用记数技术。它们依据的思想是:对任何

“活”的对象,一定能最终追溯到其存活在堆栈或静态存储区之中的引用。这个引用链条可能会

穿过数个对象层次。由此,如果从堆栈和静态存储区幵始,遍历所有的引用,就能找到所有

“活”的对象。对干发现的每个引用,必须追踪它所引用的对象,然后是此对象包含的所有引用,

如此反复进行,直到“根源于堆栈和静态存储区的引用”所形成的嗯络全部被访问为止。你所

访问过的对象必须都是“活”的。注意,这就解决了“交互自引用的对象组”的问题——这种

现象根本不会被发现,因此也就被自动回收了。

        在这种方式下,Java虚拟机将采用一种自适应的垃圾回收技术。至于如何处理找到的存活

对象,取决干不同的Java虚拟机实现。有一种做法名为停止-复制(stop-and-copy)。这意味

着,先暂停程序的运行(所以它不属于后台回收模式),然后将所有存活的对象从当前堆复制

到另一个堆,没有被复制的全部都是垃圾。当对象被复制到新堆时,它们是一个挨一个的,所

以新堆保持紧凑排列,然后就可以按前述方法简单、直接地分配新空间了。

        当把对象从一处搬到另一处时,所有指向它的那些引用都必须修正。位于堆或静态存储区

的引用可以直接被修正,但可能还有其他指向这些对象的引用,它们在遍历的过程中才能被找

到(可以想像成有个表格,将旧地址映射至新地址)。

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

然后得在这两个分离的堆之间来回捣腾,从而得维护比实际需要多一倍的空间。某些Java虚拟

机对此问题的处理方式是,按需从堆中分配几块较大的内存,复制动作发生在这些大块内存

之间。

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

尽管如此,复制式回收器仍然会将所有内存自一处复制到另一处,这很浪费。为了避免这种情

形,一些 Java 虚拟机会进行检查:要是没有新垃圾产生,就会转换到另一种工作模式(即“自

适应”)。这种模式称为标记-清扫( mark-and-sweep ) , Sun 公司早期版本的 Java 虚拟机使用

了这种技术。对一般用途而言,“标记-清扫”方式速度相当慢,但是当你知道只会产生少全垃圾

甚至不会产生垃圾时,它的速度就很快了。

        “标记-清扫”所依据的思路同样是从堆栈和静态存储区出发,迫历所有的引用,进而找出所

有存活的对象。每当它找到一个存活对象,就会给对象设一个标记,这个过程中不会回收任何

对象。只有全部标记工作完成的时候,清理动作才会开始。在清理过程中,没有标记的对象将

披释放,不会发生任何复制动作。所以剩下的堆空间是不连续的,垃圾回收器要是希望得到连

续空间的话,就得重新整理剩下的对象。

        ‘停止-复制”的意思是这种垃圾回收动作不是在后台进行的;相反,垃圾回收动作发生的同

时,程序将会被暂停。在 Sun 公司的文档中会发现,许多参考文献将垃圾回收视为低优先级的

后台进程,但事实上垃圾回收器在 Sun 公司早期版本的 Java 虚拟机中并非以这种方式实现

的。当可用内存数里较低时, Sun 版本的垃圾回收器会暂停运行程序,同样,‘标记-清扫”工作

也必须在程序暂停的情况下才能进行。

        如前文所述,在这里所讨论的 Java 虚拟机中,内存分配以较大的“块”为单位。如果对象较

大,它会占用单独的块。严格来说,“停止-复制”要求在释放旧有对象之前,必须先把所有存活

对象从旧堆复制到新堆,这将导致大量内存复制行为。有了块之后,垃圾回收器在回收的时候

就可以往废弃的块里拷贝对象了。每个块都用相应的代数( generadon count )来记录它是否还

存活。通常,如果块在某处被引用,其代数会增加;垃圾收器将对上次回收动作之后新分配的

块进行整理。这对处理大量短命的临时对象很有帮助。 垃圾回收器会定期进行完整的清理动作

——大型对象仍然不会被复制(只是其代数会增加),内含小型对象的那些块则被复制并整

理。Java 虚拟机会进行监视,如果所有对象都很稳定,垃圾回收器的效率降低的话,就切换

到“标记-清扫”方式.同样, Java 虚拟机会跟踪”标记-清扫”的效果,要是堆空间出现很多碎片,

就会切换回“停止-复制”方式。这就是“自适应”技术,你可以给它个罗嗦的称呼:“自适应的、分

代的、停止-复制、标记-清扫”式垃圾回收器。

         Java 虚拟机中有许多附加技术用以提升速度。尤其是与加载器操作有关的,被称为“即时” 

( Just - In - Time , JIT)编译器的技术。这种技术可以把程序全部或部分翻译成本地机器码(这

本来是 Java 虚拟机的工作),程序运行速度因此得以提升。当需要装载某个类(通常是在为该

类创建第一个对象)时,编译器会先找到其 .class文件,然后将该类的字节码装入内存。此时,

有两种方案可供选择。一种是就让即时编译器编译所有代码。但这种做法有两个缺陷:这种

加载动作散落在整个程序生命周期内,累加起来要花更多时间;并且会增加可执行代码的长

度(字节码要比即时编译器展开后的本地机器码小很多〕,这将导致页面调度,从而降低程序

速度。另一种做法称为惰性评估(lazy evaluation),意思是即时编译器只在必要的时候才编译

代码。这样,从不会被执行的代码也许就压根不会被JIT所编译。新版JDK中Java HotSpot的技

术就采用了类似方法,代码每次被执行的时候都会做一些优化,所以执行的次数越多,它的

速度就越快。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,539评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,911评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,337评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,723评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,795评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,762评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,742评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,508评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,954评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,247评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,404评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,104评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,736评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,352评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,557评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,371评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,292评论 2 352

推荐阅读更多精彩内容