第二章 垃圾收集器与内存分配策略

2.1 判断对象已经死亡的两种方式

2.1.1 引用计数法

概念:每一个对象都有一个计数器,当被一个引用指向的时候就把计数器加一。当一个引用失效就减一。所以说当一个对象的计数器为零的时候表示对象不在使用了。

问题:当对象出现循环引用的问题时,无法解决。

2.1.2 可达性分析算法

概念:通过一系列的“GC Roots” 的对象作为起始点,从这些节点开始向下搜索,搜索走过的路线成为引用链,当一个对象到GC Roots没有任何引用链相连,则证明此对象是不可用的。

GC Roots:

  1. 虚拟机栈中的引用对象(栈帧中的本地变量表)
  2. 方法区中类静态属性引用的对象。
  3. 方法区中常量引用的对象。
  4. 本地方法栈中JNI引用的对象。

2.1.3 再谈引用

几种引用的类型:

强引用:就是我们常见的创建对象的方式,只要强引用还存在,垃圾回收器永远不会回收掉引用的对象。

软引用:有用但非必须的对象。在系统将要发生内存溢出异常的时候,将会把这些对象列进回收范围进行第二次回收,如果这次回收还没有足够的内存,才会抛出内存 溢出异常。SoftReference类来实现软引用。

弱引用:当垃圾收集器发生时,无论内存是否充足还是不充足直接就回收掉。WeakReference类实现弱引用。

虚引用:无法通过虚引用来区的一个对象的实例。唯一的目的就是这个对象回收的时候会受到一个系统通知。

2.1.4 生存还是死亡

  1. 在可达性分析中不可达的对象,也并不一定是非死不可的。
  2. 要真正宣布一个对象死亡,至少要经历两次标记过程。
    • 如果对象在进行可达性分析之后发现没有与GC Roots相链的引用链,进行第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。当对象没有覆盖finalize()方法,或者方法已经被执行过一次,虚拟机将这两种情况都视为不需要执行。
  3. 如果这个对象有必要执行finalize方法,对象会被放到一个叫做F-Queue的队列中。
  4. 将由虚拟机创建一个低优先级的Finalizer线程去执它(不保证这个方法一定会运行完)。
  5. finalize()方法是对象逃脱死亡的最后一次机会。
  6. 接下来GC将对F-Queue中的对象进行第二次标记,如果对象要在finalize中拯救了自己(重新与引用链上的的任何一个对象奖励关联就可),那么第二次标记就会将它移除即将回收的集合,如果还是没有逃脱基本上就会被回收了。

2.2 垃圾回收算法

2.2.1 标记—清除算法

概念:从名字可以看出,这个算法主要是两个流程,标记—清除。首先会标记出所有需要回收的对象,在标记完成后进行统一回收。

存在两个问题:

  1. 效率问题:标记和清除两个过程效率都特别低。
  2. 空间问题:空间碎片太多。

2.2.2 复制算法

概念:该算法应用在新生代,新生代内存分为三块:Eden、Form、To区。比例为8:1:1。

存在的问题:当对象存活率较高的情况下,需要进行比较多的复制操作,效率会变低。

复制算法过程:

  1. 对象的内存分配主要在新生代的 Eden Space 和 Survivor Space 的 From Space(Survivor 目

    前存放对象的那一块),少数情况会直接分配到老生代(空间分配担保)。

  2. 当新生代的 Eden Space 和 From Space 空间不足时就会发生一次 GC,进行 GC 后,Eden

    Space 和 From Space 区的存活对象会被挪到 To Space,然后将 Eden Space 和 From

    Space 进行清理。

  3. 如果 To Space 无法足够存储某个对象,则将这个对象存储到老生代。

  4. 在进行 GC 后,使用的便是 Eden Space 和 To Space 了,如此反复循环。‘

  5. 当对象在 Survivor 区躲过一次 GC 后,其年龄就会+1。默认情况下年龄到达 15 的对象会被

    移到老生代中。

2.2.3 标记整理算法

概念:标记过程仍然与标记——清除算法一样。但是后续不是直接对可回收对象进行清理,而是让所有存活对象都向一端移动。然后直接清理掉端边界以外的内存。

主要应用在老年代。

2.2.4 分代收集算法

目前市面上大部分虚拟机都是分代收集算法。

2.3 垃圾收集器

在这里插入图片描述

2.3.1 Serial收集器

概念:最基本的收集器,单线程收集器,它在进行垃圾收集的时候,会暂停其他的所有工作线程,知道它结束。对于限定单个 CPU 环境来说,没有线程交互的开销,可以获得最高的单线程垃圾收集效率,因此 Serial垃圾收集器依然是 java 虚拟机运行在 Client 模式下默认的新生代垃圾收集器。(但是目前来说还是没有用到过的,太恐怖了,你的程序运行一个小时的时候会莫名其妙的暂停5分钟)

2.3.2 ParNew 收集器

概念:它是Serial收集器的多线程版本。

它是许多运行在Server模式下的虚拟机中首选的新生代收集器,除了有一个很重要的原因是,只有他能与CMS收集器配合工作。

2.3.3 Parallel Scavenge收集器

概念:它是一个新生代收集器,它也是使用复制算法的收集器。并行的多线程收集器。它的目标是达到一个可控制的吞吐量。吞吐量= 用户代码运行时间 / cpu总运行时间。

2.3.4 Serial Old收集器

概念:是Serial收集器的老年代版本,单线程收集器 ,使用标记整理算法。(主要是给Client模式使用)

2.3.5 Paraller Old收集器

概念:Paraller Old是Paraller Scavenge 收集器的老年代版本,使用多线程和标记整理算法。

2.3.6 CMS收集器

概念:它是一种以回去最短回收停顿时间为目标的收集器。使用标记清除算法,但是比之前面的更加复杂一些,整个步骤分为四步:

  1. 初始标记
  2. 并发标记
  3. 重新标记
  4. 并发清除

其中初始标记和重新标记这两个步骤仍然需要Stop the World。初始标记仅仅是标记一下GC ROots能直接关联到的对象。,并发标记阶段就是进行GC Roots Tracing 的过程。而重新标记阶段是为了修正并发标记期间因用户 程序继续运作而导致标记产生变动的那一部分对象的标记记录。

2.3.7 G1收集器

特性:

  • 并行和并发
  • 分代收集
  • 空间整合
  • 可预测的停顿

运行步骤:

  1. 初始标记
  2. 并发标记
  3. 最终标记
  4. 筛选回归
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值