如何确定垃圾?

正文


如何确定垃圾?

前面已经提到 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. 【转载】Java性能优化之JVM GC(垃圾回收机制)

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

  2. 性能测试三十五:jvm垃圾回收-GC

    垃圾回收-GC 三个问题 哪些内存需要回收? 什么时候回收? 如何回收? YoungGC和FullGC: 新生代引发的GC叫YoungGC 老年代引发的GC叫FullGC FullGC会引起整个Jvm ...

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

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

  4. 修改Tomcat的jvm的垃圾回收GC方式为CMS

    修改Tomcat的jvm的垃圾回收GC方式 cp $TOMCAT_HOME/bin/catalina.sh $TOMCAT_HOME/bin/catalina.sh.bak_20170815 vi $ ...

  5. Java 中级 学习笔记 2 JVM GC 垃圾回收与算法

    前言 在上一节的学习中,已经了解到了关于JVM 内存相关的内容,比如JVM 内存的划分,以及JDK8当中对于元空间的定义,最后就是字符串常量池等基本概念以及容易混淆的内容,我们都已经做过一次总结了.不 ...

  6. JVM学习——垃圾回收GC(学习过程)

    JVM学习-垃圾回收(GC) 2020年02月19日06:03:56,开始学习垃圾回收,学习资料来源(张龙老师的JVM课程) JVM内存数据区域知识复习 学习垃圾回收之前,要对JVM内部的内存区域有详 ...

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

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

  8. Java 垃圾回收(GC) 泛读

    Java 垃圾回收(GC) 泛读 文章地址:https://segmentfault.com/a/1190000008922319 0. 序言 带着问题去看待 垃圾回收(GC) 会比较好,一般来说主要 ...

  9. JVM GC机制

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

  10. 深入浅出 JVM GC(3)

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

随机推荐

  1. QT 子文件的建立(pri)

    QT 在做项目的时候有时会有许多不同种类的文件,如果这些文件放在一起会显得特别乱,我们可以将文件用文件夹分类,这样会比较有条理. 1. 在项目文件夹下建立新的文件夹,并在文件夹中添加文本文档将后缀改为 ...

  2. nginx和ftp搭建图片服务器

    一.需要的组件 图片服务器两个服务: Nginx(图片访问): 1.http服务:可以使用nginx做静态资源服务器.也可以使用apache.推荐使用nginx,效率更高. 2.反向代理 实现 负载均 ...

  3. SpringBoot使用thymeleaf案例

    1 编写application.properties文件 spring.thymeleaf.prefix=classpath:/templates/ spring.thymeleaf.suffix=. ...

  4. Tensorflow细节-P290-命名空间与tensorboard上的节点

    讲解几个重点知识 1.对于tf.get_variable()中的reuse,意思是,如果有名字一模一样的变量,则对这个变量继续使用,如果没有名字一模一样的变量,则创建这个变量 2.options=ru ...

  5. linux学习8 运维基本功-Linux获取命令使用帮助详解

    一.Linux基础知识 1.人机交互界面: a.GUI b.CLI:[login@hostname workdir]# COMMAND 2.命令知识 通用格式:# COMMAND  OPTIONS A ...

  6. [RN] React Native 使用 FlatList 实现九宫格布局 GridList

    React Native 使用 FlatList 实现九宫格布局 先看图片演示实例: 本文以图片列表为例,实现九宫格布局! 主要有两种方法: 1)方法一: 利用FlatList的 numColumns ...

  7. 洛谷 P1012 拼数

    P1012 拼数 标签 字符串 排序 NOIp提高组 1998 云端 难度 普及- 时空限制 1s / 128MB 题目描述 设有n个正整数(n≤20),将它们联接成一排,组成一个最大的多位整数. 例 ...

  8. 2017.10.2 国庆清北 D2T1 (a*b)|x

    在电脑上后面仨点过不了,要用I64d,lld会炸.但是洛谷上要用lld,LINUX系统没有I64d /* 求一个数对满足 (a*b)|n,也就是求三个数 a*b*c=n,那么求1~n之间的,就是a*b ...

  9. python学习笔记二:(python3 logging函数中format说明)

    背景,在学习logging时总是遇到无法理解的问题,总结,尝试一下更清晰明了了,让我们开始吧! logging模块常用format格式说明 %(levelno)s: 打印日志级别的数值 %(level ...

  10. DML 语言

    数据操纵语言(Data Manipulation Language, DML)是SQL语言中,负责对数据库对象运行数据访问工作的指令集. 以INSERT.UPDATE.DELETE三种指令为核心,分别 ...