算法 自动采集列表( jvm怎么知道堆里面的对象是无用数据,的基本算法)

优采云 发布时间: 2021-12-25 18:19

  算法 自动采集列表(

jvm怎么知道堆里面的对象是无用数据,的基本算法)

  jvm的三种算法和10个垃圾采集

  jvm如何知道堆中的对象是无用数据,有两种方式:

  1.引用计数方法:

  每个对象都有一个引用计数属性,新的引用计数加1,引用释放时计数减1,计数到0就可以回收。这种方法简单,不能解决循环引用的问题对象之间。

  2. 关注GC Roots

  (可达性分析):从GC Roots开始向下搜索,搜索所经过的路径称为参考链。当一个对象没有通过任何引用链连接到GC Roots时,证明该对象不可用,即不可达对象。

  jvm的三种基本算法

  1.1 标记-扫描算法(Mark-Sweep)

  一块内存,要恢复的数据,直接标记,清除

  1.2 复制算法(Copying)

  将一块内存中的数据直接复制到另一块内存中,然后清理之前的内存区域

  1.3 Mark-Compact 算法(Mark-Compact)

  将内存中的数据移动并标记到内存一侧进行清理

  1.4 代采集

算法

  注意,这个算法是根据不同代的对象被清除时使用的算法,将内存堆从物理上和逻辑上划分为年轻代和老年代的一种算法

  10种垃圾采集

  算法就是GC的垃圾采集

的策略,垃圾采集

器就是按照算法进行垃圾处理的具体实现。

  2.1 个串行采集

  串行(serial)垃圾采集

器是最基础的采集

器,发展历史最长;

  JDK1.3.1是新一代HotSpot合集的唯一选择;

  串行采集

器直到JDK1.7,它仍然是运行在Client模式下的JAVA虚拟机默认的新一代采集

器。它也有优于其他采集

器的优点:简单高效(相对于其他采集

器的单线程)。对于仅限于单个 CPU 的环境,Serial 采集

器没有线程交互开销,因此专注于垃圾采集

是很自然的。获得最高的单线程采集

效率。在用户的桌面应用场景中,分配给虚拟机管理的内存一般不会很大,采集

新一代的几十兆甚至一两百兆(只有新一代使用的内存,桌面应用基本没有大),暂停时间可以控制在几十毫秒以内,最多一百毫秒。只要不经常发生,这种停顿是可以接受的。因此,Serial采集

器是运行的不错选择。

  Serial采集

器的运行图如下: stw:stop-the-word 停止所有工作线程;使用复制算法;

  

  注意:这个采集

器,随着内存越来越大,执行效率太慢。比如一个人刚开始住在5平方米的房子里,房子打扫得很快。住500平米的房子,打扫屋子的时间过长,这种单线程不能用,以后会有多线程版本-ParNewcollector

  2.2 系列老采集器

  和Serial相比,Serial Old是老年代用的垃圾采集

器,也是单线程的,不过算法不是copy,而是Mark-Compact标记排序算法,也是stw:暂停所有线程为垃圾采集

;

  所以Serial和Serial Old的结合,在服务器环境下可用内存一般都不大(几十M到一两百M),不适合现在的大内存

  2.3ParNew 采集

  ParNew 垃圾采集

器是串行采集

器的改进多线程版本(因为内存不断增加)。除多线程外,其余行为和特性与串行采集

器相同。实现算法与Serial(复制算法)完全相同。在stw下执行;

  但是如果CPU数量为1或小于4,这种类型的采集

器的性能不会比Serial好。因为去掉了上下文切换,占用了用户线程的CPU时间片,导致用户线程变慢

  在Server模式下,ParNew采集

器是一个非常重要的采集

器,因为除了Serial之外,目前只能和CMS采集

器配合使用;CMS是在JDK1.5中推出的HotSpot的第一个真正含义,互联网上的并发(Concurrent)采集

器第一次使垃圾采集

线程与用户线程(基本)同时工作;

  1)CMS是老年代的采集

器,但是不能和JDK1.4中已经存在的新一代采集

器Parallel Scavenge一起工作;

  2) 因为Parallel Scavenge(和G1)不使用传统的GC采集

器代码框架,而是独立实现;而其他类型的采集

器共享部分框架代码;

  设置参数

  "-XX:+UseConcMarkSweepGC":指定使用CMS后,默认使用ParNew作为新一代采集

器;

  “-XX:+UseParNewGC”:强制指定使用ParNew;

  “-XX:ParallelGCThreads”:指定ParNew默认开启的垃圾回收线程数、回收线程数和CPU数

  2.4.并行老

  这是 Serial Old 的多线程版本。它用于老年代的采集

器。它也是一种mark-and-sort算法,是stw的执行集合。但如果 CPU 数量少,性能同样糟糕。但现在PC或服务器CPU的数量不再是性能瓶颈限制,所以目前它与Parallel Scavenge的合作是吞吐量优先场景的首选采集

器选择。

  2.5Parallel Scavenge

  相比ParNew,无法与cms结合的新一代垃圾采集

器。PS也是一种复制算法。它与前两个采集

器的最大区别在于它专注于吞吐量而不是延迟。也称为吞吐量优先采集

器。其中,吞吐量=运行用户代码的时间/(运行用户代码的时间+垃圾采集

时间)。

  主要使用场景:主要适用于后台计算而不是过多的交互任务。高吞吐量可以最有效地利用CPU时间,尽快完成程序计算任务。当然,如果要减少暂停时间,吞吐量也会相应受到影响。

  2.6 内容管理系统

  CMS,Concurrent Mark Sweep,这是一个真正的并发采集

器,即在线程执行过程中也可以进行垃圾采集

的采集

器。在一些对响应时间要求高的应用或网站中,用户程序不能有长时间的停顿,在这种场景下可以使用CMS。分为四个过程,1个初始标记,2个并发标记,3个重新标记,4个并发清理

  CMS执行流程图

  

  CMS采用多种方式尽可能减少GC的暂停时间,减少用户程序的暂停。

  在减少暂停时间的同时,牺牲了 CPU 吞吐量。因为并发占用了大量的cpu资源

  这是暂停时间和性能的权衡,可以简单理解为时间的“空间(性能)”

  CMS是一个连接过去和未来的采集器

  以下是非分代采集

  2.7 G1(垃圾优先)

  在JDK7中,它加入了JVM采集

器家族,成为HotSpot的关键垃圾采集

技术。和优秀的CMS垃圾采集

器一样,G1也是一个专注于最小延迟的垃圾采集

器。也适用于大容量堆内存的垃圾回收。官方推荐使用G1,而不是选择CMS。G1最大的特点就是引入了partition的思想,弱化了代的概念,合理利用了垃圾采集

各个周期的资源,解决了其他采集

器甚至CMS的很多缺陷。

  G1采集

器是一个垃圾采集

器,比之前的更好,有真正的突破。其实G1中还是保留了代的概念,但实际上新生代和老年代并没有物理上的分离。在 G1 中,内存空间被划分为区域。所谓新生代和老年代是由区域组成的。同时,G1 不需要与其他采集

器配合使用,它可以自己处理所有内存区域。总的来说,它不是一代采集器

,而是一款一体式采集器

。这也是JVM内存管理和垃圾回收的一个发展趋势。我们可以从下面的 zgc 中更清楚地看到这种变化。

  G1采用mark-organize算法,避免CMS内存碎片问题,实现垃圾时间可控。它是一个优秀的采集器

。即便如此,从2004年第一篇论文发表到实际商用,也是jdk1.7。实施并不那么容易。

  G1的工作过程:

  初始标记:这个过程类似于CMS的第一个过程,只是标记了与GC Root相关的对象。

  并发标记:这个过程需要很长时间来分析GC Root对所有对象的可达性分析。从GC Root节点遍历所有对象会很耗时,实际上JVM并没有这样做。JVM 使用Remembered Set 来保存对象引用的调用信息。在可达性分析中,只需要同时遍历记忆集即可,不需要从根节点开始一一遍历。

  最终标记:由于并发标记阶段,用户线程仍在工作,这会导致标记出现一些偏差。这时候就需要通过remembered set log来记录这些变化。在这个阶段,更改被合并到记忆集中。完成最后的标记。

  过滤清除:通过标记排序算法,根据用户配置的回收时间,以及维护的优先级列表,先采集

取值最高的区域。采集

阶段基于标记组织和复制算法实现

  2.8 ZGC

  zgc 是 jdk11 中最新发布的垃圾采集

器。完全没有代的概念,先说一下它的优点,官方的就是不碎片化,时间可控,大堆。

  学习连接

  2.9 雪兰多

  Shenandoah 是一个并发和并行的垃圾采集

器;和ZGC一样,它也是一个低暂停时间的垃圾采集

器,但是ZGC是基于彩色指针实现的,而Shenandoah GC是基于布鲁克斯指针的。

  其实业界早就出现了低暂停GC,只是Java来的比较晚

  Azul's Zing中的C4 GC土豪选择

  oracle中的HotSpot ZGC JDK11选择

  R说ZGC说他们抄了Azul,两者是等价的。

  可以参考这篇文章了解如何连接

  2.10 厄普西隆

  Java 11 新的 Epsilon 垃圾采集

  Epsilon(A No-Op Garbage Collector)垃圾采集

器控制内存分配,但不执行任何垃圾采集

。一旦java的heap用完,直接关闭jvm。设计的目的是提供一个完全负向GC的实现,分配有限的内存分配,最小化内存占用的消耗和内存吞吐量的延迟时间。一个好的实现是隔离代码更改,不影响其他 GC,将其他 JVM 代码更改到最少。

  仅供参考

  链接:Epsilon 学习链接

  最后附上各采集器的组合流程图

  

  终于找到一个很不错的博客,写了很多jvm的知识,可以去学习下

  添加链接描述

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线