JVM垃圾回收

看到垃圾回收,首先你会想到什么?

1、什么是垃圾?

2、哪些地方的垃圾需要被回收?

3、如何定位垃圾?

4、如何回收垃圾?

5、什么时候回收垃圾?

下面,我们将带着这5个问题来进行分析。

1、什么是垃圾?

JVM中的垃圾指的是无用的内存,这些内存中的数据若在后续处理过程中不再被使用,那么我们将是为垃圾进行回收,以保证有足够的内存可用。

程序在运行过程中会存在两个问题:

1)内存溢出:是指内存空间分配不足

2)内存泄露:是指内存使用完后无法被回收

2、哪些地方的垃圾需要被回收?

线程私有内存区域(程序计数器、虚拟机栈、本地方法栈)会随着线程的结束而释放,栈中的栈帧随着方法的进入和退出有条不紊的执行者进栈和出栈操作,每个栈帧中的分配多少内存在编译期便已确定,因此无需对该区域进行垃圾回收。

线程共享内存区域(方法区和Java堆)需要分配的内存大小只有在运行期才知道,因此这部分的内存是动态分配和回收的,也是我们接下来需要对垃圾内存回收的区域。

3、如何定位垃圾?

因为我们垃圾回收的主要区域是针对于Java堆(又称为GC堆),这部分区域主要存放的是Java对象的实例,因此判断内存是否可以被回收只需要确认实例对象已经不被使用,即对象是否存活。

判断对象是否的方法有两种,一种是引用计数算法,另一种是可达性分析算法。下面我们来介绍一下这两中算法的优缺点。

1)引用计数算法

首先我们来说一下这个算法的实现思想:为每个对象添加一个引用计数器,每当有一个地方引用它时,计数器的值加1,当引用失效时,计数器的值减1。当计数器的值为0时表示该对象没有被引用。

上述实现思想看起了一点毛病都没有,实现起来也是非常的简单,而且效率也比较高,但是既然会有其他的算法被使用,那么该算法也就一定有他的缺点。

优点:实现简单且效率高

缺点:无法处理对象互相循环引用的情况。

对象的互相循环引用?听起来不太容易理解,那我们就来举个例子吧

public class ReferenceCountingGC {

    public Object instance = null;

    public static void testGC () {

        ReferenceCountingGC objA = new ReferenceCountingGC();

        ReferenceCountingGC objB = new ReferenceCountingGC();

        objA.instance = objB;

        objB.instance = objA;

        objA = null;

        objB = null;

        System.gc();

    }

}

上述代码中,对象A和对象B彼此引用,虽然对其句柄赋值为null,但是两个对象的引用计数器的值均为1,因此使用引用计数算法无法对上述两个对象进行回收。

2)可达性分析算法

目前主流的程序语言的实现中都称是通过可达性分析算法来判断对象是否存活。其算法的基本思想是:通过一系列被称为”GC Roots“的对象作为起始点,开始向下搜索,搜索所走过的路径成为引用链,当一个对象到GC Roots没有任何的引用链时,则证明此对象是不可用的。

上面提到了一个“GC Roots”,那么哪些对方的对象是可以作为GC Roots呢?

在Java语言中,可作为GC Roots的对象包括:

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

  b. 本地方法栈中JNI(native方法)引用的对象

  c. 方法区中类静态属性引用的对象

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

4、如何回收垃圾?

关于如何回收垃圾这一部分我们要分为两部分进行讲解:垃圾收集算法垃圾收集器

第一部分 垃圾收集算法

垃圾收集算法主要包括三种算法:标记-清除算法复制算法标记-整理算法

另外还有分代收集算法,这种算法没有特别的思想,而是根据对象存活周期的不同将内存划分为几块,然后根据对应内存区域的特点采用适当的收集算法。

下面我们分别对上述三种算法进行分析说明。

1)标记-清除算法

实现思路:分为两个阶段,第一个阶段是标记,如何标记(定位)垃圾已经在第3点中介绍过了。第二个阶段是直接清除。

标记-清除算法的执行过程如图所示。它存在两个不足之处:

      a. 效率问题,标记和清除l两个过程的效率都不高。

      b. 空间问题,标记清除之后会产生大量不连续的内存碎片,可能会导致在后续分配较大对象是没有足够的空间导致出发一次内存收集的动作。

图片引用于https://www.jianshu.com/p/5d612f36eb0b
图片引用于https://www.jianshu.com/p/5d612f36eb0b

2)复制算法

实现思路:将内存按照大小划分为两块,每次只使用其中的一块,当另一块的内存用完了,就将还存活的对象复制到另一块的上面,然后再把当前内存区域一次清理掉。

优点:内存分配时只需要按照顺序分配即可,实现简单,运行效率高。

缺点:牺牲了一半的内存空间

目前商业虚拟机并非将内存空间按照1:1的比例来划分内存,而是将内存分为一块较大空间的Eden空间和两块较小的Survivor空间,每次使用Eden和其中一块Survivor。回收时将Eden和Survivor中还存活的对象一次性复制到另一块Survivor空间。

HotSpot虚拟机默认Eden和Survivor的大小比例是8:1,每次新生代中可用的内存空间为整个新生代容量的90%。这里面临着两个问题:一是什么场景适合使用该方式,二是如果Eden和Survivor存活的对象超过10%该怎么处理?

        适合使用的场景:在绝大数情况下,Eden和Survivor在回收后存活的对象小于10%

        超过10%的处理方式:内存分配担保。我们将内存空间分为新生代(Eden和Survivor)和老年代,如果Eden和Survivor回收后的存活对象超过10%,则直接进入老年代。

图片引用于https://www.jianshu.com/p/5d612f36eb0b
图片引用于https://www.jianshu.com/p/5d612f36eb0b

3)标记-整理算法

实现思路:类似于标记-清除算法,不同的是不直接对可回收的对象进行清理,而是让所有存活的对象都想前一端移动,然后清理掉端边界以外的内存。

优点:不会产生大量不连续的内存空间,适用于老年代

图片引用于https://www.jianshu.com/p/5d612f36eb0b
图片引用于https://www.jianshu.com/p/5d612f36eb0b

4)分代收集算法

将Java堆划分为新生代和老年代。

新生代在每次垃圾收集时会有大批对象死去,适合采用复制算法。

老年代对象存活率高且没有额外空间进行分配担保,因此适合采用标记-整理算法。

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

推荐阅读更多精彩内容

  • GC区域Eden Survivor(from,to), Old Gen和Perm Gen VM区域总体分两类,he...
    Fitz_Lee阅读 400评论 0 0
  • 0. 前言 JVM笔记系列,以JDK1.7为基准,主要以《深入理解Java虚拟机》(第二版)和《Java虚拟机规范...
    郭寻抚阅读 882评论 0 3
  • JVM垃圾回收 Java堆中存放着大量的Java对象实例,在垃圾收集器回收内存前,第一件事情就是确定哪些对象是“活...
    azmohan阅读 345评论 0 0
  • 胶质瘤的分类和病理诊断 “胶质瘤”这个术语指的是具有与“正常胶质细胞”(即星形胶质细胞、少突胶质细胞和室管膜细胞)...
    咏而归怒而飞阅读 1,851评论 0 0
  • 2017.8.15 六月廿四 星期二 晴 我觉得我在乎的东西,已经越来越少了。心越大,心越累,不如放下。 但总有一...
    故园小屋阅读 189评论 0 0