正文


如何确定垃圾?

前面已经提到 JVM 可以采用 引用计数法 与 可达性分析算法 来确定需要回收的垃圾,我们来具体看一下这两种算法:

  • 引用计数法

该方法实现为:给每个对象添加一个引用计数器,每当有一个地方引用它时,引用计数值就+1,当引用失效时,引用计数值就-1,任何时刻引用计数值为0的对象就可以被回收,当一个对象被垃圾收集器收集时,被它引用的对象引用计数值就-1,所以在这种方法中一个对象被垃圾收集会导致后续其他对象的垃圾收集行动。

优点:简单、高效;

缺点:当两个对象相互引用的时候就无法回收,导致内存泄漏。

  • 可达性分析法

为了解决对象间相互引用问题,Java 采用了可达性分析法,基本实现思路为:通过一系列 "GC Roots" 对象作为起点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到 "GC Roots" 没有任何引用链相连时,则称该对象是不可达的,此时,该对象还处于缓刑阶段,要真正宣判一个对象为可回收对象,至少要经历两次标记过程。

哪些对象可以作为 "GC Roots" ?

1、通过System Class Loader或者Boot Class Loader加载的class对象
2、处于激活状态的线程
3、栈中的对象
4、JNI栈中的对象
5、JNI中的全局对象
6、正在被用于同步的各种锁对象
7、JVM自身持有的对象,比如系统类加载器等

垃圾回收算法

通过上面面试者的回答,我们已经知道垃圾收集算法主要包括:复制算法、标记清除算法、标记整理算法、分代回收算法,我们来具体看一下:

  • 复制算法

该方法实现为:将内存分为大小相等的两块,每次只使用其中一块,当这一块内存满了后将存活的对象复制到另一块上去,把已使用的内存清掉。如图所示:

优点:简单、高效、不会产生内存碎片;

缺点:可用内存减少为原来的一半,造成内存浪费。

  • 标记清除算法

该方法实现分为两个阶段,标注和清除,标记阶段找到所有可访问的对象,做个标记 ;清除阶段遍历堆,把未被标记的对象回收。如图所示:

缺点:碎片化严重。

  • 标记整理算法

该方法不直接对可回收对象进行清理,而是让所有可用的对象都向一端移动,然后直接清理掉边界外的对象,解决了标记清除算法带来的碎片化问题。如图所示:

  • 分代回收算法

分代回收算法是目前大部分 JVM 所采用的方法,其核心思想是根据对象存活的生命周期不同,将内存划分为不同的区域,一般情况下将 GC 堆划分为新生代和老年代;老年代的特点是:对象生命周期较长,每次垃圾回收时只有少量对象需要被回收;新生代的特点是:对象大部分朝生夕死,生命周期短,每次垃圾回收时都有大量对象需要被回收;因此,可以根据不同区域选择不同的算法,使垃圾回收更加合理、高效,如:新生代采用效率较高的复制算法,老年代采用不会产生内存碎片,也不会发生内存浪费的标记整理算法。

垃圾收集器

常用的垃圾收集器都有哪些呢?我们来具体看一下:

  • Serial 垃圾收集器

Serial 曾经是 JDK1.3.1 之前新生代唯一的垃圾收集器;Serial 是一个单线程的收集器,在进行垃圾收集的同时,必须暂停其他所有的工作线程,直到垃圾收集结束;但同时 Serial 也是简单高效的,对于限定单个 CPU 环境来说,没有线程交互的开销,可以获得最高的单线程垃圾收集效率。

  • ParNew 垃圾收集器

ParNew 是 Serial 多线程版,也使用复制算法,除了使用多线程进行垃圾收集之外,其余的行为和 Serial 收集器完全一样。

  • Parallel Scavenge 收集器

Parallel Scavenge 是一个新生代垃圾收集器,同样使用复制算法,也是一个多线程的垃圾收集器,它重点关注的是程序达到一个可控制的吞吐量(吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)),高吞吐量可以最高效率地利用 CPU 时间,尽快地完成程序的运算任务,主要适用于在后台运算而不需要太多交互的任务。

  • Serial Old 收集器

Serial Old 是 Serial 垃圾收集器老年代版本,它是个单线程的,使用标记整理算法的收集器。

  • Parallel Old 收集器

Parallel Old 收集器是 Parallel Scavenge 的老年代版本,它是多线程的,使用标记整理算法,在 JDK1.6 开始提供使用。

  • CMS 收集器

CMS 是一种老年代垃圾收集器,其主要目标是获取最短垃圾回收停顿时间,和其它老年代使用标记整理算法不同,它使用多线程的标记清除算法;其运作过程比较复杂,整个过程分为6个步骤,包括:初始标记(CMS initial mark)、并发标记(CMS concurrent mark)、并发预清理(CMS-concurrent-preclean)、重新标记(CMS remark)、并发清除(CMS concurrent sweep)、并发重置(CMS-concurrent-reset),其中初始标记、重新标记这两个步骤仍然需要暂停其它工作线程,初始标记仅仅只是标记一下 "GC Roots" 能直接关联到的对象,速度很快,并发标记阶段就是进行 "GC Roots" 追踪的过程,而重新标记阶段则是为了修正并发标记期间,因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远比并发标记的时间短。

  • G1 收集器

G1 是 JVM 垃圾收集器理论进一步发展的产物,相比与 CMS 收集器,G1 基于标记整理算法,不会产生内存碎片;其次,还可以非常精确控制停顿时间,在不牺牲吞吐量前提下,实现低停顿垃圾回收;G1 收集器避免全区域垃圾收集,它把堆内存划分为大小固定的几个独立区域,并且跟踪这些区域的垃圾收集进度,同时在后台维护一个优先级列表,每次根据所允许的收集时间,优先回收垃圾最多的区域;区域划分和优先级区域回收机制,确保 G1 收集器可以在有限时间获得最高的垃圾收集效率。

小伙子,你真的清楚 JVM GC ?的更多相关文章

  1. 一夜搞懂 | JVM GC&内存分配

    前言 本文已经收录到我的Github个人博客,欢迎大佬们光临寒舍: 我的GIthub博客 学习导图 一.为什么要学习GC&内存分配? 时代发展到现在,如今的内存动态分配与内存回收技术已经相当成 ...

  2. 如何避免后台IO高负载造成的长时间JVM GC停顿(转)

    译者著:其实本文的中心意思非常简单,没有耐心的读者建议直接拉到最后看结论部分,有兴趣的读者可以详细阅读一下. 原文发表于Linkedin Engineering,作者 Zhenyun Zhuang是L ...

  3. 【转载】Java性能优化之JVM GC(垃圾回收机制)

    文章来源:https://zhuanlan.zhihu.com/p/25539690 Java的性能优化,整理出一篇文章,供以后温故知新. JVM GC(垃圾回收机制) 在学习Java GC 之前,我 ...

  4. JVM GC机制

    垃圾收集主要是针对堆和方法区进行. 回收机制: 现在的JVM基本都使用分代回收机制,把堆中内存区域分为新生代,老年代. 新生代: Eden(80%) Survivor0(10%) Survivor1( ...

  5. 深入浅出 JVM GC(3)

    # 前言 在 深入浅出 JVM GC(2) 中,我们介绍了一些 GC 算法,GC 名词,同时也留下了一个问题,就是每个 GC 收集器的具体作用.有哪些 GC 收集器呢? Serial 串行收集器(只适 ...

  6. 深入浅出 JVM GC(2)

    # 前言 在 深入浅出 JVM GC(1) 中,限于上篇文章的篇幅,我们留下了一个问题 : 如何回收? 这篇文章将重点讲述这个问题. 在上篇文章中,我们也列出了一些大纲,今天我们就按照那个大纲来逐个讲 ...

  7. JVM 自带性能监测调优工具 (jstack、jstat)及 JVM GC 调优

    1. jstack:占用最多资源(CPU 内存)的Java代码 https://www.cnblogs.com/chengJAVA/p/5821218.html https://blog.csdn.n ...

  8. 理解JVM GC

    理解JVM GC对于我们把控Java应用有很大的帮助.下面我从运维角度,把网上的JVM相关的资料整理如下,以加深对JVM GC的理解.如有错误的地方,请看官指正. JVM内存使用分类 JVM的内存分区 ...

  9. Java性能优化之JVM GC(垃圾回收机制)

    Java的性能优化,整理出一篇文章,供以后温故知新. JVM GC(垃圾回收机制) 在学习Java GC 之前,我们需要记住一个单词:stop-the-world .它会在任何一种GC算法中发生.st ...

随机推荐

  1. Codeforces Round #563 (Div. 2)C

    C. Ehab and a Special Coloring Problem 题目链接:http://codeforces.com/contest/1174/problem/C 题目 You're g ...

  2. sort和sorted深入理解----引子:多维列表,如何实现第一个元素升序,第二个元素降序

    一.列表内建方法--sort() 作用:就地对列表排序(直接在原列表上做排序) 语法: list.sort(func=None, key=None, reverse=False) 当reverse=F ...

  3. Git项目迁移

    代码项目迁移步骤 1.将原有项目重命名,old 2.新建一个项目,名字为原本的项目名称,new 3.使用特殊方式克隆代码 # old.git为原项目重命名后的git链接 git clone --mir ...

  4. Cisco packet tracer下dhcp的配置的vlan的应用

    话不多说,先上拓扑图. pc0和pc1分别接在三层交换机的F0/1.F0/2接口,ser接在F0/24接口,用ser用作dhcp的服务器. 0x01:配置server0 先配置server的IP地址. ...

  5. 面试中常见的算法之Java中的递归

    1.方法定义中调用方法本身的现象2.递归注意实现 1) 要有出口,否则就是死递归 2) 次数不能太多,否则就内存溢出 3) 构造方法不能递归使用3.递归解决问题的思想和图解: 分解和合并[先分解后合并 ...

  6. java虚拟机-JDK8-废弃永久代(PermGen)迎来元空间(Metaspace)

    一.背景 1.1 永久代(PermGen)在哪里? 根据,hotspot jvm结构如下(虚拟机栈和本地方法栈合一起了): 上图引自网络,但有个问题:方法区和heap堆都是线程共享的内存区域. 关于方 ...

  7. BZOJ 2115:Xor(线性基+DFS)

    题目链接 题意 中文题意 思路 因为存在环和重边,边来回走是没有意义的,因此最终的答案应该是一条从1到n的路径权值异或上若干个环的权值,那么难点在于如何选取这些环的权值使得最终的答案更优. 使用到线性 ...

  8. (转)User-Agent的由来(原来这么有意思)

    你是否好奇标识浏览器身份的User-Agent,为什么每个浏览器都有Mozilla字样?Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 ( ...

  9. Kafka Eagle V1.3.4更新预览

    1.概述 Kafka Eagle是一款开源的Kafka集群监控系统,源代码托管在Github.目前Kafka Eagle已更新到V1.3.4版本,域名已经统一更新为http://www.kafka-e ...

  10. 关于String重写的hashcode的代码分析

    public int hashCode() { int h = hash; if (h == 0 && value.length > 0) { char val[] = valu ...