Java知识复习之JVM垃圾回收和算法(4)

JVM中垃圾回收也是一个很重要的知识点,今天来学习回顾一下。

我们首先要明白,JVM为什么需要垃圾回收。我觉得首先,Java这门语言和C语言不一样的是JVM会帮助我们管理对象,所以我们可以之间New一个对象使用就好了,不像C语言的指针,还需要我们自己去管理,但JVM管理这些对象就会产生一些“垃圾”其实不是真的垃圾,而且那些我们已经不使用的对象,使用对于这些不需要的对象JVM就需要处理他们,不然内存是远远不够的。

GC垃圾回收要干的三件事

  • 【1.哪些内存需要回收?】
  • 【2.什么时候去回收?】
  • 【3.怎么去回收】

第一件事:如何确认垃圾,也就是哪些需要进行回收

  • 【方法一:引用计数法】:在Java中,引用和对象是有关联的。如果要操作对象则必须要引用进行。因此,很显然一个简单的办法是通过引用计数来判断一个对象是否可以回收。即一个对象如果没有任何与之关联的引用,即他们的引用计数都不为0,则说明对象不太可能再被用到,那么这个对象就是可回收对象。
  • 【方法二:可达性分析】:为了解决引用计数法的循环引用问题,Java使用了可达性分析的方法。通过一系列的"GC roots"对象作为起点搜索。如果在"GC roots"和一个对象之间没有可达路径,则称对象是不可达的。但不可达对象不等价于可回收对象,不可达对象变为可回收对象至少要经历两次标记过程。两次标记后仍然是可回收对象,则将面临回收。

标记清除算法(Mark-Sweep)

  • 【基本概述】:该垃圾回收算法是最基础的垃圾回收算法,分为两个阶段:标注和清除。标记阶段标记出所有需要回收的对象,清除阶段回收被标记的对象所占用的空间。但这样会产生一个很大的问题:内存碎片化严重,因为这样等于在在原地把垃圾清理,而不是把垃圾统一到清除。

复制算法(copying)

  • 【概述】:为了解决Mark-Sweep算法产生的内存碎片缺陷而提出来的。
  • 【具体实现】:按内存容量将内存划分成为等大小的两块,每次只使用其中一块,当这一块内存满后将尚存活的对象复制到另外一块上去,把已使用的内存清掉。
  • 【弊端】:这种算法虽然简单,内存效率高,不容易产生碎片,但最大的问题就是可用的内存被压缩成一半了,且存活对象增加的话,copying算法的效率也会大大的降低。

标记整理算法(Mark-Compact)

  • 【概述】:是结合上面两种算法,为了避免缺陷而提出的。
  • 【实现】:依旧采取标记,在标记阶段和标记算法一样,但标记后不是之间清理对象,而是将存活对象移向内存的一端,然后再清除边界外的对象。

分带收集算法

分代收集法是目前大部分JVM所采用的方法,其核心思想是根据对象存活的不同生命周期将内存划分成不同的域,一般情况下将GC堆划分成老年代和新生代。老年代的特点是每次垃圾回收时只有少量的对象需要被回收,新生代的特点是每次垃圾回收时都有大量的垃圾被回收,因此此时可以根据不同的区域选择 不同的算法

  • 【新生代和复制算法】:大部分JVM的GC对于新生代都采取Copying算法,因为新生代中每次垃圾回收都要回收大部分对象,即要复制的操作比较少,但通常并不是按照1:1来划分新生代。一般将新生代划分为一块较大的Eden区和两块较小的Survivor空间(From Space,To Space)。每次使用Eden空间和其中的一块Survivor空间,当进行回收时,将该两块空间中还存活的对象复制到另外一块Survivor空间中。
  • 【老年代和标记复制算法】:因为老年代每次回收的对象很少量,因此采用Mark-Compact算法。
  • 【注意的几点】
  • 【1】Java虚拟机提到过的处于方法区的永生带,它是用来存储class类,常量,方法描述等。对永生代的回收主要包括废弃的常量和无用的锁。
  • 【2】对象的内存分配主要是在新生代的Eden区和From Space,少数情况会直接分配到老年代。
  • 【3】新生代进行CG时,会将Eden区和From Space区存活的对象放到To Space区,然后对Eden区和From Space区进行清理,如果此时To Space无法足够存储某个对象,则将这个对象放入到老年代中。
  • 【4】新生代在进行CG后,使用的便是Eden区和To Space区了,然后反复循环。
  • 【5】当对象在Survivor区躲过一次GC后,其年龄就会+1,默认情况下年龄到达15的对象就会被移到老年代中。

垃圾收集器

新生代使用到的是复制算法和标记清除算法,老年代使用的是标记整理算法。因此Java虚拟机中针对新生代和老年代分别提供了多种不同的垃圾收集器,JDK1.6中的Sun HotSpot虚拟机中的垃圾收集器如下:
在这里插入图片描述

  • 【Serial垃圾收集器(单线程、复制算法)】:Serial是最基本的垃圾收集器,使用复制算法,曾经是jdk1.3.1之前新生代唯一的垃圾收集器。其是一个单线程的收集器,它不但只会使用一个CPU或者一条线程去完成垃圾收集工作,并且在收集的同时必须暂停其他所有的工作,直到垃圾收集结束。Serial垃圾收集器虽然
    在收集垃圾过程中需要暂停所有其他工作,但它简单高效,对于限定的单个CPU环境来说,没有线程的交互开销,可以获取到最高的单线程垃圾收集效率,因此Serial垃圾收集器依然是java虚拟机在Clinet模式下默认的新生代垃圾收集器。
  • 【ParNew垃圾收集器(Serial+多线程)】:ParNew垃圾收集器其实是Serial的多线程版本,也使用的复制算法,除了使用多线程进行垃圾收集之外,取余的和Serial一样。ParNew收集器默认开启和CPU数目相同的线程数,可以通过-XX:ParallelGCTheards参数来限制垃圾收集器的线程数。ParNew是很多Java虚拟机运行在Server模式下的新生代的默认垃圾收集器。
  • 【Parallel Scavenge收集器(多线程复制算法、高效)】:该收集器重点关注的是程序达到一个可控制的吞吐量(吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)),高吞吐量可以最高效率地利用CPU时间,尽可能完成程序的运算任务,主要适用于在后台运算而不需要太多交互任务。自适应调节策略也是ParallelScavenge收集器和ParNew收集器的一个重要区别。
  • 【Serial Old收集器(单线程标记整理算法)】:该收集器是Serial垃圾收集器老年代版本,同样是单线程的收集器,使用的是标记-整理算法。这个收集器也主要运行在Clinet默认的java虚拟机默认的老年代垃圾收集器。在Server模式下,主要有两个用途:1)在jdk1.5之前和新生代的parallel Scavenge收集器搭配使用。2)作为老年代中使用CMS收集器的后备垃圾收集方案。
  • 【Parallel Old收集器(多线程标记整理算法)】:该收集器是Parallel Scavenge的老年代版本。在 JDK1.6 之前,新生代使用 ParallelScavenge 收集器只能搭配年老代的 Serial Old 收集器,只能保证新生代的吞吐量优先,无法保证整体的吞吐量,Parallel Old 正是为了在年老代同样提供吞吐量优先的垃圾收集器,如果系统对吞吐量要求比较高,可以优先考虑新生代 Parallel Scavenge和年老代 Parallel Old 收集器的搭配策略。
  • 【CMS收集器(多线程标记清除算法)】:Concurrent mark sweep收集器是一种老年代垃圾收集器,其最主要的目标是获取最短垃圾回收停顿时间。CMS的工作机制相比其他垃圾收集器更加复杂,分为4个阶段:在这里插入图片描述
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值