JVM垃圾回收(GC)

1. 判断对象是否可以被回收

  • 引用计数法:每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时可以回收。此方法简单,但无法解决对象相互循环引用的问题

    // 循环引用
    Node a=new Node();
    Node b=new Node();
    a.next=b;
    b.next=a;
  • 可达性分析:从GC Roots开始向下搜索,搜索所走过的路径称为引用链。当一个对象到GC Roots没有任何引用链时,则证明此对象时不可用的,可以被回收。

为了避免对象相互循环引用的问题,JVM中使用可达性分析判断对象是否可以被回收。

2. 四种引用

2.1 强引用(StrongReference)

大部分引用都是强引用,是使用最普遍的引用。强引用不会被垃圾回收器回收,始终是可达状态。当内存空间不足时,JVM宁可抛出OOM异常,使程序异常终止,也不会通过回收具有强引用的对象来解决内存不足的问题。这是造成Java内存泄漏的重要原因之一。(联系ThreadLocal例子)

2.2 软引用(SoftReference)

对于具有软引用的对象,当内存空间足够时,垃圾回收器不会回收它,若内存空间不够了,就会回收这些对象的内存。软引用可以用来实现内存敏感的高速缓存。

2.3 弱引用(WeakReference)

只要垃圾回收机制运行并发现了具有弱引用的对象,不管当前内存空间是否足够,都会回收该对象的内存。垃圾回收线程的优先级很低,不一定很快发现只具有弱引用的对象。

2.4 虚引用(PhantomReference)

主要作用是用于跟踪对象被垃圾回收的活动。不能单独使用,必须与引用队列(ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它具有虚引用,就会在回收对象的内存前把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是否已经加入虚引用来了解被引用的对象是否要被垃圾回收。

3. 判断废弃常量和无用的类

废弃常量:运行时常量池主要回收废弃常量。如果当前没有任何对象引用该常量,就说明该常量是废弃常量。

无用的类:需要同时满足3个条件。

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

4. 垃圾收集算法

4.1 标记-清除算法(Mark-Sweep)

原理:首先标记出可以回收的对象,在标记完成后统一回收所有被标记的对象。

特点内存碎片化严重、效率低

4.2 复制算法(Copying)

原理:按内存容量将内存划分为大小相同的两块。每次只使用其中的一块,当这一块内存满了之后,将存活的对象复制到未使用的一块中,然后把使用的那一块一次清理。

特点:不易产生内存随便,但效率大大降低。

4.3 标记-整理算法(Mark-Compact)

原理:首先标记出可以回收的对象,然后将存活对象移动至内存的一端,然后清除掉边界外的对象。

特点:根据老年代特点提出的一种标记算法。

4.4 分代收集算法

当前虚拟机的垃圾收集都采用分代收集算法。

新生代,每次收集都会有大量对象死去,所以采用复制算法,只需复出少了对象的复制成本就可以完成每次垃圾收集。

老年代,对象存活几率比较高,每次垃圾回收是时只有少量对象需要被回收,因此采用标记-整理算法进行垃圾收集。

5. 垃圾收集器

JVM针对新生代和老年代分别提供了不同的垃圾收集器。

5.1 Serial收集器(单线程+复制算法)

Serial收集器是最基本的垃圾收集器。Serial是单线程的收集器,只会使用一条垃圾收集线程去完成垃圾收集工作,同时在进行垃圾收集工作时不许暂停其他所有的工作线程("Stop the World"),直到收集结束。

新生代采用复制算法,老年代采用标记-整理算法。

Serial收集器简单高效,对于限定单个CPU环境来说没有线程交互的开销,可以获得最高的单线程垃圾收集效率,因此Serial垃圾收集器时JVM运行在Client模式下默认的新生代垃圾收集器。

5.2 ParNew收集器(Serial+多线程)

ParNew收集器是Serial收集器的多线程版本(多线程并发),除了使用多线程进行垃圾收集外,其余行为和Serial收集器完全一样。

新生代采用复制算法,老年代采用标记-整理算法。

ParNew收集器是运行在Server模式下的JVM的首要选择,除了Serial收集器,只有它能与CMS收集器配合工作。

5.3 Parallel Scavenge收集器

与ParNew收集器类似,但Parallel Scavenge收集器的关注点是吞吐量(高效率地利用CPU)。CMS等垃圾收集器地关注点是用户线程的停顿时间(提高用户体验)。所谓吞吐量就是CPU中用于运行用户代码的时间与CPU总消耗时间的比值。

Parallel Scavenge提供了两个参数用于精确控制吞吐量,分别是控制最大垃圾收集停顿时间的-XX: MaxGCPauseMillis参数以及直接设置吞吐量大小的-XX: GCTimeRatio参数。

5.4 Serial Old收集器(单线程+标记-整理算法)

Serial收集器的老年代版本。它具有两大用途:一种是在JDK1.5及以前的版本中与Parallel Scavenge收集器搭配使用,另一种是作为CMS收集器的后备方案。

5.5 Parallel Old收集器(多线程+标记-整理算法)

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

5.6 CMS收集器(多线程+标记-清除算法)

CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器,非常符合在注重用户体验的应用上使用。 CMS收集器是第一款真正意义上的并发收集器,第一次实现了让垃圾回收线程与用户线程(基本上)同时工作。CMS收集器是基于标记-清除算法的。其运行过程包括四个步骤:

  • 初始标记暂停所有其他线程,并记录下直接与GC Roots相连的对象,速度很快;
  • 并发标记:同时开启GC和用户线程,用一个闭包结构去记录可达对象。但在这个阶段结束,这个闭包结构并不能保证包含当前所有的可达对象。因为用户线程可能会不断地更新引用域,所以GC线程无法保证可达性分析的实时性,因此这个算法里会跟踪记录这些发生引用更新的地方。该阶段无需暂停工作线程
  • 重新标记:重新标记阶段就是为了修正并发标记期间因为用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段的时间稍长,远远比并发标记近阶段的时间短。该阶段仍需要暂停所有工作线程,;
  • 并发清除:开启用户线程,同时GC线程开始清除GC Roots不可达对象,无需暂停工作线程

优点:并发收集、低停顿

缺点:对CPU资源敏感;无法处理浮动垃圾;使用的"标记-清除"会导致收集结束时产生大量内存碎片。

5.7 G1收集器

G1(Garbage First)是面向服务器的垃圾收集器,主要针对配备多核处理器及大容量内存的机器,以极高概率满足GC停顿时间要求的同时还具备高吞吐量性能特征

特点:

  • 并行与并发
  • 分代收集:可以独立管理整个GC堆,但也保留了分代的概念;
  • 空间整合:基于标记-整理算法,不产生内存碎片;
  • 可预测的停顿:相比于CMS,G1可以能建立可预测的停顿时间模型,在不牺牲吞吐量的前提下实现低停顿的垃圾回收。

G1收集器运行步骤大致分为:初始标记;并发标记;最终标记;筛选回收

G1收集器避免全区域垃圾收集,把堆内存划分为大小固定的几个独立区域,并且跟踪这些区域的垃圾收集进度,同时在后台维护一个优先级列表,每次根据所允许的收集时间,优先回收垃圾最多的区域。区域划分和优先级区域回收机制,确保G1收集器可以在有限时间获得最高的垃圾收集效率。

JVM垃圾回收(GC)的更多相关文章

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

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

  2. JVM 垃圾回收GC Roots Tracing

    1.跟搜索算法: JVM中对内存进行回收时,需要判断对象是否仍在使用中,可以通过GC Roots Tracing辨别. 定义: 通过一系列名为”GCRoots”的对象作为起始点,从这个节点向下搜索,搜 ...

  3. JVM垃圾回收(GC)流程

    /* 首先介绍一下JVM中堆内存的组成: JVM堆内存主要由三部分组成: (1)新生代: 伊甸园区,存活区,伸缩区 (2)老年代: 老年区,伸缩区 (3)元空间(永久代): 元空间,伸缩区 注意:JD ...

  4. JVM垃圾回收——GC

    一.JVM内存分配与回收 下图为堆内存结构图(注意:元数据区(MetaData )实际上不属于堆): 1.对象优先在Eden区分配 大多数情况下,对象在新生代中Eden区分配.当Eden区没有足够空间 ...

  5. JVM垃圾回收GC

    1.堆的分代和区域 (年轻代)Young Generation(eden.s0.s1  space)    Minor GC (老年代)Old Generation (Tenured space)   ...

  6. JVM—垃圾回收GC算法

    1 GC算法简介 算法 特点 标记-清除 分为"标记"和"清除"两个阶段 复制 可以解决效率问题,将可用的内存按容量划分为大小相等的两块. 标记-整理 先标记. ...

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

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

  8. Java:JVM垃圾回收(GC)机制

    JVM垃圾回收算法 1.标记清除(Mark-Sweep) 原理: 从根集合节点进行扫描,标记出所有的存活对象,最后扫描整个内存空间并清除没有标记的对象(即死亡对象)适用场合: 存活对象较多的情况下比较 ...

  9. .Net平台GC VS JVM垃圾回收

    前言 不知道你平时是否关注程序内存使用情况,我是关注的比较少,正好借着优化本地一个程序的空对比了一下.Net平台垃圾回收和jvm垃圾回收,顺便用dotMemory看了程序运行后的内存快照,生成内存快照 ...

随机推荐

  1. Go的100天之旅-08字符串

    目录 简介 UTF-8字符 字符串的常用操作 简介 字符串在各种编程语言中都是很基础的一种类型,在Go中字符串简单理解就是一个数组,数组里面的元素是byte类型.因此基本上拥有类似数组的全部特性.例如 ...

  2. C++语法小记---多重继承

    多重继承 工程中不建议使用多继承,因为多继承带来的问题比带来的便利多,已被放弃 问题一:多重继承的对象,向上获取指针时,有不同的地址 ----无法解决 问题二:菱形继承问题,导致成员冗余 ----虚继 ...

  3. Monster Audio 使用教程 (六) 发送音轨的设置

    因为最近有些用户,不太清楚怎么发送给混响音轨,所以这里我简单介绍一下. Monster Audio的音轨,主要分为两种类型: 1.白色推子:表示普通音轨 2.蓝色推子:表示“可接收发送音轨”,其他音轨 ...

  4. 深入探究JVM之垃圾回收器

    @ 目录 前言 正文 一.垃圾收集算法 标记-复制 标记-清除 标记-整理 分代回收 二.常用的垃圾回收器 Serial/SerialOld ParNew Parallel Scavenge/Para ...

  5. Go 中读取命令参数的几种方法总结

    前言 对于一名初学者来说,想要尽快熟悉 Go 语言特性,所以以操作式的学习方法为主,比如编写一个简单的数学计算器,读取命令行参数,进行数学运算. 本文讲述使用三种方式讲述 Go 语言如何接受命令行参数 ...

  6. Java中包装类Test类测试出错的解决方法(JUnit5)

    import org.junit.jupiter.api.Test; public class TestJunit { public static void main(String[]args) {  ...

  7. 学习JavaScript数据结构与算法 2/15

    第一章 JavaScript简介 js不同于C/C++,C#,JAVA,不是强类型语言. 通常,代码质量可以用全局变量和函数的数量来考量(数量越多越糟).因此,尽可能避免使用全局变量. JS数据类型 ...

  8. JDBC(1)-数据库连接和CRUD操作

    关于jdbc的全部jar包 链接:https://pan.baidu.com/s/1peofgu89SpepTTYuZuphNw 提取码:vd5v 一.获取数据库连接 1. Driver接口介绍 ja ...

  9. 牛客练习赛63 C 牛牛的揠苗助长 主席树 二分 中位数

    LINK:牛牛的揠苗助长 题目很水 不过做法很多 想到一个近乎O(n)的做法 不过感觉假了 最后决定莽一个主席树 当然 平衡树也行. 容易想到 答案为ans天 那么一些点的有效增长项数为 ans%n. ...

  10. Java8的@sun.misc.Contended注解

    @sun.misc.Contended 介绍 @sun.misc.Contended 是 Java 8 新增的一个注解,对某字段加上该注解则表示该字段会单独占用一个缓存行(Cache Line). 这 ...