垃圾回收基础

垃圾回收(Garbage Collection,GC)是虚拟机内存管理很重要的一个模块,它帮助虚拟机在技术层面上做到了内存动态分配后的回收。垃圾回收主要发生在线程公有的区域。GC主要完成这样三件事情:

  • 确定哪些内存需要回收;

  • 确定待回收的内存在何时回收;

  • 如何来做垃圾回收。

接下来就以如何做这三件事情为切入点,详细介绍一下GC的相关基础。

注:为什么垃圾回收发生在线程公有区域?
私有区域会随着线程的消亡而消亡,但是共有区域不会,公有区域内存的回收需要GC来完成。了解Java内存模型的小伙伴都知道,堆和方法区是公有的,所以GC目标区域在堆和方法区。

如何确定对象已死?

堆中几乎存放着Java程序中所有的对象实例,对于回收堆上的内存来说,确定哪些内存需要回收实质就是确定哪些对象已经死了,而后续的垃圾回收也就是将这些已死对象的内存做回收。那么,如何确定对象已死?

引用计数算法

确定一个对象是否已经死了就是看这个对象是不是没有引用了。在很多资料上都看到了判断对象是不是有引用的算法是这样子的:给对象添加一个引用计数器,一旦有地方引用它时,计数器值+1,引用失效时,计数器值-1,当引用计数器值为0时,该对象不再被引用。客观的说,引用计数算法实现很简单,判断效率也很高,但是,假如存在对象之间互相引用,这个算法就解决不了了,所以Java的GC并没有选用该算法来管理内存。

举个简单的例子:对象A和B都有私有属性instance,赋值令A.instance = B,B.instance = A,A和B互相引用。


demo

GC日志:


GC日志

从GC日志可以看出,虚拟机并没有因为a和b互相引用就不回收它们,这也说明虚拟机并不是通过引用计数算法来判断对象是否存在引用的。

根搜索算法

以GC Roots对象作为起始点,从这些节点依次向下搜索,如果当前对象到GC Roots没有任何的路径相连(对象不可达)时,那么,当前对象没有引用。

引用链:对象到GC Roots的走过的路径

在Java中,以下对象可作为GC Roots:

  1. Java虚拟机栈(栈帧中的本地变量表)中引用的对象;

  2. 本地方法栈中引用的对象;

  3. 方法区中的常量引用的对象;

  4. 方法区中的静态属性引用的对象。

根搜索算法中不可达的对象,是不是就非死不可呢?其实并不是的,要真正宣告一个对象死亡,至少要经过两次标记。在这里必须要多嘴几句说说finalize。

finalize

有过面试经历的人,可能都被问到了final,finally和finalize的区别。前两个关键字比较常用,在这里就不再做介绍了。finalize是一个方法名,Java允许使用finalize方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作,所以很多文章中又称它为析构函数的替代者。那么finalize方法是何时何地被调用呢?每次GC都会调用它么?

  • finalize方法调用过程
    待回收的对象被标记出来之后,会对这些对象做一次筛选,看对象是否有必要执行finalize方法。判断对象是否有必要执行该方法主要有以下两个依据:

    • 对象有没有覆盖finalize方法;

    • 对象已覆盖finalize方法,检查finalize方法是否被虚拟机调用过,如果已被调用,就不需要再次执行。

    验证待回收对象有必要执行finalize方法后,这个对象将会被放置到队列F-Queue中,并且会被虚拟机的单独线程Finalizer执行。一定需要注意的是,这里的执行不代表执行成功,只触发finalize方法,不承诺等待该方法执行结束。为什么这么设计呢?

    • 对象finalize方法执行时间较高,会导致F-Queue中的其他对象等待时间较长;

    • 如果程序员不小心,在finalize方法的实现中写了个死循环,这时候F-Queue中的其他对象会一直处于等待状态,甚至导致整个GC崩溃。

注:看到这里大致已经了解了finalize的执行过程以及执行次数,千万别认为finalize方法会一直都被执行,其实它只会被执行一次,一旦它在上次GC已经被执行,以后就不会再执行,除非你重启系统。

  • finalize使用案例
    finalize使用案例

    运行结果:

    案例通过finalize方法成功的实现了逃脱被GC,但是从运行结果可以看出,第一次确实成功的逃脱了,但是第二次就没那么好运了,被GC掉了。这也能说明finalize方法只能被执行一次。

如何回收内存?

在确定需要回收的对象之后,接下来就将这些内存做回收。先来看看垃圾回收算法吧,本文只简要介绍垃圾回收算法思想,至于实现后面文章会给出较详细的分析。

  • 标记 - 清除算法
    标记 - 清除算法是最基础的垃圾收集算法。它分为两个阶段:

    • 标记阶段:标记出所有待回收的对象;

    • 清除阶段:清除掉所有被标记的对象;

    该算法实现过程简单,成本低,但是它有这样几个缺点:

    • 效率较低;

    • 标记清除并没有对内存做过压缩整理,这样会导致清除后出现大量的内存碎片,空间内存碎片较多可能会导致在后续程序需要分配较大对象时无法找到足够的连续内存空间而不得不提前触发一次GC。

    为什么说它是最基础的垃圾收集算法,是因为后续的垃圾收集算法都是基于该算法思路并对其不足之处改进得到的。

  • 复制算法
    为了改善标记 - 清除算法的效率问题,复制算法出现了。它将可用内存划分为大小固定的两块,每次只使用其中的一块,当这一块内存使用完了,就将还活着的对象复制到另外一块内存上,一次性清理掉已使用过的内存空间。这样子做的好处就是每次的垃圾收集只对其中一块内存进行回收,效率提升,而且,复制算法在回收内存不会产生垃圾碎片。但是,该算法有个不好处就是它将原来的内存缩小了。一般young区采用该算法来回收内存。

注:HotSpot默认Eden区和Survivor区大小比例为8:1,至于为什么设置这个比例是因为young区的对象98%都是朝生夕死的。当然,JVM也提供参数以供使用者来更改Eden区和Survivor区的大小比例。

  • 标记 - 整理算法
    由于每次要执行较多的复制操作,复制收集算法在对象存活率比较高的区域做内存回收就比较费劲了。更重要的一个点就是如果不想浪费一部分内存空间,就需要额外的空来进行分配担保,来应对被使用的内存中所有对象都存活的情况。根据old区的特点,标记 - 整理算法被提出。该算法的标记的过程与标记 - 清除算法一致,但是,后续的过程就有区别了,标记 - 整理算法不会直接对已标记的对象做内存回收,而是会让所有还存活的对象移动到一端,然后清除掉这一端边界以外的内存。

垃圾回收算法的思想到这里就分析完毕了,要想完整的了解垃圾回收,还需要了解垃圾回收载体 - 垃圾收集器。考虑到垃圾收集器类型较多,分析篇幅较大,就不再本文做相关分析了,会在后续的文章就垃圾收集器做详细的分析。

到这里,垃圾回收的相关基础内容就介绍完毕了,欢迎大家继续关注后续的垃圾回收更深层次的介绍。

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

推荐阅读更多精彩内容