JVM原理2

  1. 回收废弃常量
  • 回收废弃常量与回收 Java 堆中的对象非常类似。以常量池中字面量的回收为例,假如一个字符串 “abc” 已经进入了 常量池中,但是当前系统没有任何一个 String 对象是叫做 “abc” 的,换句话说,就是没有任何 String 对象引用常量池中的 “abc” 常量,也没有其他地方引用了这个字面量,如果这时发生内 存回收,而且必要的话,这个 “abc” 常量就会被系统清理出常量池。常量池中的其他类(接 口)、方法、字段的符号引用也与此类似。




  1. 可以回收无用的类
  • 该类所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例。
  • 加载该类的ClassLoader已经被回收。
  • 该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。




  1. 标记 - 清除算法 Mark-Sweep
  • 算法分 标记 清除 两个阶段
  • 首先标记出所有需要回收的对象,在标记完成后统一回收所有 被标记的对象。
  • 不足有两个:一个是效率问题,标记和清除两个过程的效率都不高;
  • 另一个是 空间问题,标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程 序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾 收集动作。
     




  1. 复制算法
  • 将可用内存按容 量划分为大小相等的两块,每次只使用其中的一块。
  • 当这一块的内存用完了,就将还存活着 的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。
  • 这样使得每次都是 对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指 针,按顺序分配内存即可,实现简单,运行高效。
  • 只是这种算法的代价是将内存缩小为了原 来的一半,未免太高了一点。
     




  1. 标记 - 整理算法 Mark-Compact
  • 复制收集算法在对象存活率较高时就要进行较多的复制操作,效率将会变低。更关键的
    是,如果不想浪费 50% 的空间,就需要有额外的空间进行分配担保,以应对被使用的内存中
    所有对象都 100% 存活的极端情况,所以在老年代一般不能直接选用这种算法。
  • 根据老年代的特点,提出了另外一种 标记 - 整理 Mark-Compact )算法,标记过程
    仍然与 标记 - 清除 算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存
    活的对象都向一端移动,然后直接清理掉端边界以外的内存。
     




  1. 垃圾收集器
     




  1. Serial 收集器
  • 单线程的收集器,但它 单线程 的意义并不仅仅说明它只会使用一个 CPU 或一条收集线程去完成垃圾收集工作, 更重要的是在它进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束。
  • “Stop The World” ,这项工作实际上是由虚拟机在后台自动发起和自动 完成的,在用户不可见的情况下把用户正常工作的线程全部停掉,这对很多应用来说都是难 以接受的。
  • 虚拟机运行在 Client 模式下的默认新生代收集器。
  • 它也有着优于其他收集器的地方:简单而高效(与其他收集器的单线程比),对于限定单个 CPU 的环境来说, Serial 收集器由于没有线程交互的开销,专心做垃圾收集自然可以获得最 高的单线程收集效率。在用户的桌面应用场景中,分配给虚拟机管理的内存一般来说不会很 大,收集几十兆甚至一两百兆的新生代(仅仅是新生代使用的内存,桌面应用基本上不会再 大了),停顿时间完全可以控制在几十毫秒最多一百多毫秒以内,只要不是频繁发生,这点 停顿是可以接受的。所以, Serial 收集器对于运行在 Client 模式下的虚拟机来说是一个很好的 选择。




  1. ParNew 收集器
  • Serial 收集器的多线程版本,除了使用多条线程进行垃圾收集之 外,其余行为包括 Serial 收集器可用的所有控制参数 、收集算法、 Stop The World 、对 象分配规则、回收策略等都与 Serial 收集器完全一样,在实现上,这两种收集器也共用了相 当多的代码。
  • 运行在 Server 模式下的虚拟机中首选的新生代收集器。
  • 其中有一个与性能无关但 很重要的原因是,除了 Serial 收集器外,目前只有它能与 CMS 收集器配合工作。




  1. Parallel Scavenge 收集器
  • Parallel Scavenge 收集器是一个新生代收集器,它也是使用复制算法的收集器,又是并行
    的多线程收集器。
  • Parallel Scavenge 收集器的目标则是达到 一个可控制的吞吐量( Throughput )。
  • 所谓吞吐量就是 CPU 用于运行用户代码的时间与 CPU 消耗时间的比值,即吞吐量 = 运行用户代码时间 / (运行用户代码时间 + 垃圾收集时间),虚 拟机总共运行了 100 分钟,其中垃圾收集花掉 1 分钟,那吞吐量就是 99%
  • 停顿时间越短就越适合需要与用户交互的程序,良好的响应速度能提升用户体验,而高
    吞吐量则可以高效率地利用 CPU 时间,尽快完成程序的运算任务,主要适合在后台运算而不
    需要太多交互的任务。




  1. Serial Old 收集器
  • Serial Old Serial 收集器的老年代版本。
  • 同样是一个单线程收集器,使用 标记 - 算法。
  • 这个收集器的主要意义也是在于给 Client 模式下的虚拟机使用。
  • 如果在 Server 模式 下,那么它主要还有两大用途:一种用途是在 JDK 1.5 以及之前的版本中与 Parallel Scavenge 收集器搭配使用 ,另一种用途就是作为 CMS 收集器的后备预案,在并发收集发生 Concurrent Mode Failure 时使用。




  1. Parallel Old 收集器
  • Parallel Old Parallel Scavenge 收集器的老年代版本,使用多线程和 标记 - 整理 算法。
  • 在注重吞吐量以及 CPU 资源敏感的场合,都可以优先考虑 Parallel Scavenge Parallel Old 收集器。




  1. CMS 收集器 Concurrent Mark Sweep
  • CMS 收集器是一种以获取最短回收停顿时间为目标的收集 器。
  • 目前很大一部分的 Java 应用集中在互联网站或者 B/S 系统的服务端上,这类应用尤其重 视服务的响应速度,希望系统停顿时间最短,以给用户带来较好的体验。 CMS 收集器就非常 符合这类应用的需求。
  • CMS 收集器是基于 标记 清除 算法实现 的。
  • 整个过程分为 4 个步骤,包括:
    初始标记( CMS initial mark
    并发标记( CMS concurrent mark
    重新标记( CMS remark
    并发清除( CMS concurrent sweep
  • 初始标记、重新标记这两个步骤仍然需要 “Stop The World” 。初始标记仅仅只是 标记一下 GC Roots 能直接关联到的对象,速度很快,并发标记阶段就是进行 GC RootsTracing 的过程,而重新标记阶段则是为了修正并发标记期间因用户程序继续运作而导致标记产生变 动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远 比并发标记的时间短。
  • 由于整个过程中耗时最长的并发标记和并发清除过程收集器线程都可以与用户线程一起 工作,所以,从总体上来说, CMS 收集器的内存回收过程是与用户线程一起并发执行的。
  • 缺点:
    1. CMS 收集器对 CPU 资源非常敏感。
    2. CMS 收集器无法处理浮动垃圾( Floating Garbage ),可能出现 “Concurrent Mode            Failure” 失败而导致另一次 Full GC 的产生。
    3. 收集结束时会有大量 空间碎片产生。




  1. G1 收集器
  • G1 是一款面向服务端应用的垃圾收集器。
  • 点:
    1. 并行与并发: G1 能充分利用多 CPU 、多核环境下的硬件优势,使用多个 CPU CPU 或者 CPU 核心)来缩短 Stop-The-World 停顿的时间,部分其他收集器原本需要停顿 Java 线程执行的 GC 动作, G1 收集器仍然可以通过并发的方式让 Java 程序继续执行。
    2. 分代收集:与其他收集器一样,分代概念在 G1 中依然得以保留。虽然 G1 可以不需要其 他收集器配合就能独立管理整个 GC 堆,但它能够采用不同的方式去处理新创建的对象和已 经存活了一段时间、熬过多次 GC 的旧对象以获取更好的收集效果。
    3. 空间整合:与 CMS 标记 清理 算法不同, G1 从整体来看是基于 标记 整理 算法实 现的收集器,从局部(两个 Region 之间)上来看是基于 复制 算法实现的,但无论如何,这 两种算法都意味着 G1 运作期间不会产生内存空间碎片,收集后能提供规整的可用内存。这种 特性有利于程序长时间运行,分配大对象时不会因为无法找到连续内存空间而提前触发下一 GC
    4. 可预测的停顿:这是 G1 相对于 CMS 的另一大优势,降低停顿时间是 G1 CMS 共同的关
    注点,但 G1 除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一
    个长度为 M 毫秒的时间片段内,消耗在垃圾收集上的时间不得超过 N 毫秒,这几乎已经是实
    Java RTSJ )的垃圾收集器的特征了。
  • G1 之前的其他收集器进行收集的范围都是整个新生代或者老年代,而 G1 不再是这 样。使用 G1 收集器时, Java 堆的内存布局就与其他收集器有很大差别,它将整个 Java 堆划分 为多个大小相等的独立区域( Region ),虽然还保留有新生代和老年代的概念,但新生代和 老年代不再是物理隔离的了,它们都是一部分 Region (不需要连续)的集合。
  • G1 收集器之所以能建立可预测的停顿时间模型,是因为它可以有计划地避免在整个 Java 堆中进行全区域的垃圾收集。 G1 跟踪各个 Region 里面的垃圾堆积的价值大小(回收所获得的 空间大小以及回收所需时间的经验值),在后台维护一个优先列表,每次根据允许的收集时 间,优先回收价值最大的 Region (这也就是 Garbage-First 名称的来由)。这种使用 Region 划分 内存空间以及有优先级的区域回收方式,保证了 G1 收集器在有限的时间内可以获取尽可能高 的收集效率。
  • Java 堆分为多个 Region 后,垃圾收集 是否就真的能以 Region 为单位进行了? Region 不可能是孤立的。一个对象分配在某个 Region 中,它并非只能被本 Region 中的其 他对象引用,而是可以与整个 Java 堆任意的对象发生引用关系。那在做可达性判定确定对象 是否存活的时候,岂不是还得扫描整个 Java 堆才能保证准确性?
  • G1 收集器中, Region 之间的对象引用以及其他收集器中的新生代与老年代之间的对象 引用,虚拟机都是使用 Remembered Set 来避免全堆扫描的。 G1 中每个 Region 都有一个与之对
    应的 Remembered Set ,虚拟机发现程序在对 Reference 类型的数据进行写操作时,会产生一个 Write Barrier 暂时中断写操作,检查 Reference 引用的对象是否处于不同的 Region 之中(在分代 的例子中就是检查是否老年代中的对象引用了新生代中的对象),如果是,便通过
    CardTable 把相关引用信息记录到被引用对象所属的 Region Remembered Set 之中。当进行内 存回收时,在 GC 根节点的枚举范围中加入 Remembered Set 即可保证不对全堆扫描也不会有遗 漏。
  • G1 收集器的步骤:
    初始标记( Initial Marking
    并发标记( Concurrent Marking
    最终标记( Final Marking
    筛选回收( Live Data Counting and Evacuation
  • 初始标记阶段仅仅只是标记一下 GC Roots 能直接关联到的对象,并且修改 TAMS Next Top at Mark Start )的值,让下一阶段用户程序并发运行时,能在正确可用的 Region 中创建新对象,这阶段需要停顿线程,但耗时很短。并发标记阶段是从 GC Root 开始 对堆中对象进行可达性分析,找出存活的对象,这阶段耗时较长,但可与用户程序并发执 行。而最终标记阶段则是为了修正在并发标记期间因用户程序继续运作而导致标记产生变动 的那一部分标记记录,虚拟机将这段时间对象变化记录在线程 Remembered Set Logs 里面,最 终标记阶段需要把 Remembered Set Logs 的数据合并到 Remembered Set 中,这阶段需要停顿线 程,但是可并行执行。最后在筛选回收阶段首先对各个 Region 的回收价值和成本进行排序, 根据用户所期望的 GC 停顿时间来制定回收计划 ,这个阶段 其实也可以做到与用户程序一起并发执行,但是因为只回收一部分 Region ,时间是用户可控 制的,而且停顿用户线程将大幅提高收集效率。











































































































  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值