JVM关键总结(三)——分代与垃圾回收算法

一、分代思想

  1. 分代介绍
    JVM将堆中对象分为了新生代和老年代,默认情况下新生代占用1/3堆大小,老年代占用2/3堆大小。 在Hotspot中方法区(元空间)又称为永久代(PermGen)。

  2. 新生代
    新生代分为Eden区和Survivor区,其中Survivor区又分为From区和To区,Eden区:From区:To区 默认为 8:1:1。一般对象优先在Eden区进行内存分配,但是大对象有可能直接进入老年代。
    新对象分配空间时,如果Eden区空间够分配那就分配到Eden,不够的话就进行Minor GC,Minor GC后存活的对象将被转移到Survivor区中From区,在Survivor区中的对象会开始计算年龄(记录在对象头中4bit大小)。

    对象年龄如何计算?
    当From区满时会启动Minor GC,此时From区中存活的对象将被放到To区,需要注意的是,To区一定为空,当From区将对象转移到To区后,这时原来的From区变为To区,原来的To区变为了From区,每当进行转换一次,对象的年龄就 +1 ,当对象年龄到达最大值15时(可通过参数修改,但不能超过15)便送入老年代。

  3. 老年代
    从Survivor区生存年龄达到15(默认值)时对象就进入老年代,在老年代中主要产生Full GC,由于老年代比较稳定,因此垃圾回收不会频繁进行。

  4. (方法区)永久代
    永久代的垃圾回收主要是废弃常量和无用的类,回收废弃常量于回收Java堆中的对象很类似,例如常量池中的字符串“aaa”,如果没有任何对象引用这个“aaa”,如果此时发生内存回收必要的话会回收该字符串内存空间。

    如何判断类无用需回收呢?
    ①该类所有实例都已经被回收,即不存在该类任何实例
    ②加载该类的ClassLoader已经被回收
    ③该类对应的Class对象没有被任何地方引用,即无通过反射新建该类实例对象的可能。

    这里只是能回收,不表示一定回收。在大量使用反射、CGLib等字节码框架、动态生成JSP已经OSGI这类频繁自定义ClassLoader类的场景都需要虚拟机具备类回收功能,以保证方法区(永久代)不会溢出。

  5. 分代图
    在这里插入图片描述

二、判断对象是否可回收

  1. 引用计数法
    给对象添加一个引用计数器,每当有一个地方引用它时,计算器就加1;当引用失效时,计数器就减1;任何时刻引用计数器为0的对象将不可再被使用,即可回收。
    但是这种方法在互相引用的时候会导致无法回收,比如A引用B,B引用A,A和B的其他引用都失效了,此时A和B应该已经无用可回收了,但由于引用计数器不为零,因此仍无法回收。

  2. 可达性分析法
    目前主流的语言都是使用可达性分析法进行对象回收判断。这个算法基本思想是通过一系列称为“GC Roots”的对象作为起始点,从这些节点出发开始向下搜索,搜索走过的路径称为引用链,当一个对象没有引用链到达GC Roots时,则该对象是不可用的(图论上叫做GC Roots到该对象不可达),这些对象会被判定为可回收对象。
    GC Roots对象
    ①虚拟机栈(栈帧中局部变量表)中引用的对象
    ②方法区中类静态属性引用的对象
    ③方法区中常量引用的对象
    ④本地方法栈中native方法引用的对象

三、GC类型

  1. Minor GC(新生代GC):指发生在新生代的垃圾收集,因为Java对象大多都是朝生夕亡的,所以Minor GC很频繁,一般回收速度也比较快。

  2. Major GC / Full GC(老年代 GC):指发生在老年代的GC,出现了Major GC经常会伴随至少一次的Minor GC(不绝对,Parallel Scavenge收集器收集策略就有直接进行Major GC的策略选择过程)。Full GC一般比Minor GC慢10倍以上,执行次数也比Minor GC少

四、垃圾回收算法

  1. 标记-清除算法
    最基础的收集算法,算法分 “标记” 和 “清除” 两个阶段。首先标记出所有需要回收的对象,在标记完成后统计回收所有被标记的对象。

    算法缺点:
    ①效率问题,标记和清除两个过程效率不高
    ②空间问题,标记清除后会产生大量不连续的空闲空间(内存碎片)

    示意图:
    在这里插入图片描述

  2. 复制算法
    将内存分为大小相同的两块,每次使用只使用其中一块。当这块内存用完后就将还存活的对象复制到另一块,同时把原来的空间清理掉,这样每次内存回收都是堆内存区间的一半进行回收。

    算法缺点:
    内存利用率不高,50%以上内存处于空闲状态

    示意图:
    在这里插入图片描述

  3. 标记-整理算法
    根据老年代的特点提出的一种算法,标记过程和“标记-清除”算法一样,但是接着将所有存活对象向前移动到内存前部形成连续的占用空间,然后清理掉最后一个存活对象之后的内存。

    算法缺点:
    速度比“标记-清除”算法慢,因为比该算法多了一个整理阶段。

    示意图:
    在这里插入图片描述

  4. 分代收集算法
    目前的垃圾收集器基本都采用“分代收集”算法,实际就是根据对象存活周期不同划分内存。由于Java堆分为新生代和老年代,因此我们可以根据各代特点分别选择垃圾回收算法,实际上也就是上面几种算法的综合使用。
    新生代中,每次gc时都有大量对象被回收,所以选择复制算法,这样只需复制存活的少量对象即可完成gc任务。
    老年代对象由于较稳定,如果使用复制算法每次都会有很多对象转移,而且没有额外的空间对他进行分配担保,因此一般选择“标记-清除”算法或“标记-整理”算法。

五、笔记目录

JVM关键总结(一)——类加载机制
JVM关键总结(二)——JVM内存结构
JVM关键总结(三)——分代与垃圾回收算法
JVM关键总结(四)——垃圾回收器及调优命令与工具

参考资料:
1.《深入理解Java虚拟机第二版》——周志明
2.http://www.360doc.com/content/17/0919/14/20874412_688384439.shtml
3.https://www.cnblogs.com/Qinmp-Blog/p/5693318.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值