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. 史上最全的 jmeter 获取 jdbc 数据使用的四种方法

    jmeter使用jdbc协议获取数据库中数据,很多人都会用,因为大家在做测试的时候,有时候需要大量的用户进行登录,获取需要数据库中真实的数据用于测试,所以常常会用jdbc来获取数据库数据. 那从数据库 ...

  2. 云原生时代高性能Java框架—Quarkus(一)

    --- Quarkus&GraalVM介绍.创建并启动第一个项目 Quarkus系列博文 Quarkus&GraalVM介绍.创建并启动第一个项目 构建Quarkus本地镜像.容器化部 ...

  3. 数据库分布式事务XA规范介绍及Mysql底层实现机制

    1. 引言 分布式事务主要应用领域主要体现在数据库领域.微服务应用领域.微服务应用领域一般是柔性事务,不完全满足ACID特性,特别是I隔离性,比如说saga不满足隔离性,主要是通过根据分支事务执行成功 ...

  4. 拆招黑客!github代码库大牛们如何应对黑客攻击

    2019年05月,<个人电脑杂志>网站报道,GitHub(2018年被微软收购)代码库正遭到一名黑客的入侵(392个资源库受损,约1000名用户受到攻击,真实资料未知).据称,这名黑客先擦 ...

  5. 我们通常这样使用Linux弱口令检测!

    在Internet环境中,过于简单的口令是服务器面临的最大风险,对于管理员来说,即使找出这些弱口令账号是非常必要的,这样便于采取进一步的安全措施. 这里的话,弱口令检测需要用到一款密码破译软件--Jo ...

  6. .Net Core 项目开发中的Errors,Exceptions

    这个错误是在连接数据库的时候,没有找到对应的表, namespace TodoApi.Models { public class TodoContext : DbContext { public To ...

  7. SpringBoot集成Dubbo+Zookeeper

    目录 Spring版本 dubbo_zookeeper负责定义接口 dubbo_provider 服务提供者 dubbo_consumer服务使用者 Spring版本 不知道为啥,新创建的Spring ...

  8. MacOS工具

    原文是"池建强"的微信文章,公众号为"MacTalk" 1. Alfred 2. iTerm2 一些基本功能如下: 分窗口操作:shift+command+d( ...

  9. Python while 中简单的语句组

    Python while 中简单的语句组: 只使用 while: # 简单的语句组 a = 4 b = 8 num = 0 while a < b: print("a 比 b 小&qu ...

  10. Hadoop学习之常用输入输出格式总结

    目的 总结一下常用的输入输出格式. 输入格式 Hadoop可以处理很多不同种类的输入格式,从一般的文本文件到数据库. 开局一张UML类图,涵盖常用InputFormat类的继承关系与各自的重要方法(已 ...