Java-基础知识-GC

本文印象笔记原文版本(带重点标注)

 

jvm垃圾回收机制

 

JVM的内存空间,从大的层面上来分析包含:新生代空间(Young)和老年代空间(Old)。新生代空间(Young)又被分为2个部分(Eden区域、Survivous区域)和3个板块(1个Eden区域和2个Survivous区域)

 

1)Eden(伊甸园)区域:用来存放使用new或者newInstance等方式创建的对象,默认这些对象都是存放在Eden区,除非这个对象太大,或者超出了设定的阈值-XX:PretenureSizeThresold,这样的对象会被直接分配到Old区域。

2)2个Survivous(幸存)区域:一般称为S0,S1,理论上他们一样大。

 

 

第一次GC:

在不断创建对象的过程中,当Eden区域被占满,此时会开始做Young GC也叫Minor GC

  • 1)第一次GC时,Survivous中S0区和S1区都为空,将其中一个作为To Survivous(用来存储Eden区域执行GC后不能被回收的对象)。比如:将S0作为To Survivous,则S1为From Survivous。

  • 2)将Eden区域经过GC不能被回收的对象存储到To Survivous(S0)区域(此时Eden区域的内存会在垃圾回收的过程中全部释放),但如果To Survivous(S0)被占满了,Eden中剩下不能被回收对象只能存放到Old区域。

  • 3)将Eden区域空间清空,此时From Survivous区域(S1)也是空的。

  • 4)S0与S1互相切换标签,S0为From Survivous,S1为To Survivous。

 

第二次GC:

当第二次Eden区域被占满时,此时开始做GC

  • 1)将Eden和From Survivous(S0)中经过GC未被回收的对象迁移到To Survivous(S1),如果To Survious(S1)区放不下,将剩下的不能回收对象放入Old区域;

  • 2)将Eden区域空间和From Survivous(S0)区域空间清空;

  • 3)S0与S1互相切换标签,S0为To Survivous,S1为From Survivous。

 

第三次,第四次一次类推,始终保证S0和S1有一个空的,用来存储临时对象,用于交换空间的目的。反反复复多次没有被淘汰的对象,将会被放入Old区域中,默认15次(由参数--XX:MaxTenuringThreshold=15 决定)。

 

 

问题3:对象进入Old区域有什么坏处?

  • Old区域一般称为老年代,老年代与新生代不一样。新生代,我们可以认为存活下来的对象很少,而老年代则相反,存活下来的对象很多,所以JVM的堆内存,才是我们通常关注的主战场,因为这里面活着的对象非常多,所以发生一次FULL GC,来找出来所有存活的对象是非常耗时的,因此,我们应该避免FULL GC的发生。

 

问题6:为什么发生FULL GC会带来很大的危害?

  • 在发生FULL GC的时候,意味着JVM会安全的暂停所有正在执行的线程(Stop The World),来回收内存空间,在这个时间内,所有除了回收垃圾的线程外,其他有关JAVA的程序,代码都会静止,反映到系统上,就会出现系统响应大幅度变慢,卡机等状态。

 

对于不同的世代可以使用不同的垃圾回收算法。比如对由于年轻代存放的对象多是朝生夕死,因此可以采用标记-复制,而对于老年代则可以采用标记-整理/清除.

 

Minor GC

发生在新生代的GC为Minor GC 。在Minor GC时会将新生代中还存活着的对象复制进一个Survivor中,然后对Eden和另一个Survivor进行清理。所以,平常可用的新生代大小为Eden的大小+一个Survivor的大小。

 

Major GC

在老年代中的GC则为Major GC.

 

Full GC

通常是和Major GC等价的,针对整个新生代,老年代,元空间metaspace(java8以上版本取代perm gen)的全局范围的GC.

 


常见的垃圾回收算法有哪些?简述其原理.

 

垃圾回收从理论上非常容易理解,具体的方法有以下几种:

  • 标记-清除

  • 标记-复制

  • 标记-整理

  • 分代回收

 

1. 标记——清除算法(Mark-Sweep)

标记——清除算法是第一种使用和比较完善的垃圾回收算法,算法分为两个过程:

  • 1、标记正所有需要回收的对象

  • 2、标记完成后清除被标记的对象。其标记的过程就是判断对象有效性,执行可达性分析的过程。

 

其执行流程图大体如何下所示:

 

同样,我们也借助现实的场景进行描述。图书管里有好多人在看书,图书管理员想要收集起没有被看的书的时候,他决定让所有正在看书的人站起来,然后询问每个人:那一本书是不看的。询问完所有的人之后,同学们做下继续看书。这时候,图书管理员开始寻找所有做过标记的书,把它们收集起来。

 

缺点:

  • 1、每次进行垃圾回收时,会暂停当前用户程序的运行(类似让所有的同学站起来)

  • 2、垃圾回收器需要间隔性的检查,并且标记和清除的过程相对较慢。

  • 3、在标记清除之后可能会产生大量内存碎片,导致一旦需要为大对象分配空间时,由于找不到足够大的内存空间,而不得以引发另外一次GC过程。

 

 

2. 标记——复制算法(Mark——Copy)

  • 标记——复制存储算法通过采用双区域交替使用这种方式解决了标记——清除算法中效率低下的问题。它将可可用内存划分为两个等量的区域(使用区和空闲区),每次只使用一块。当正在使用的区域需要进行垃圾回收时,存活的对象将被复制到另外一块区域。原先被使用的区域被重置,转为空闲区。其执行流程大体如下所示:

图书管理员为了更好的发现不看的书,将图书室一分为二(A区和B区),同一时刻只有一块区域允许看书。开始时只允许在A区看书。当管理员想要回收A区不被看的书的时候,大喊一嗓子“正在看书的同学拿着你书到B区”。等所有人都到了B区后,图书管理员只要把A区的书收集起来,就完成了任务。下一次收集的时候,则是要求同学带着自己看的书从B区转移到A区。如此循环往复即可。

 

缺点:

  • 1、原有可用空间被缩小为1/2,空间利用率降低了。

  • 2、过程中也会暂停当前应用的运行。

 

 

3. 标记——整理算法(Mark——Compat)

  • 标记-复制算法在对象存活率较高的情况下就要进行较多的复制操作,更重要的是该算法浪费一般的内存空间,为了解决该问题,出现了标记——整理算法:其标记的过程和“标记-清除”算法一样,而整理的过程则是让所有存活的对象都向另外一端移动,然后直接清理掉端边界以外的内存。其执行流程大体如下所示:

缺点:

  • 1、暂停当前应用的运行,非实时性的回收。

 

4. 分代收集算法

分代收集算法理论来源于统计学。IBM公司的专门研究发现,对象的生存周期总体可分为三种:新生代、老年代和永久代。因此可以根据各个年代的特点采用适当的垃圾回收算法。

比如新生代的对象在每次垃圾时都会有大量的对象死去,只有很少一部分存活,那就可以选择标记-复制算法。另外,在新生代中每次死亡对象约占98%,那么在标记-复制算法中就不需要按照1:1的比例来划分内存区域,而是将新生代细分为了一块较大的Eden和两块较小的Survivor区域,HotSpot中默认这两块区域的大小比例为8:2。

每次新生代可用区域为Eden加上其中一块Survivor区域,共90%的内存空间,这样就只有10%的内存空间处在被闲置状态。

在进行垃圾回收时,存活的对象被转移到原本处在“空闲的”Eden区域。

如果某次垃圾回收后,存活对象所占空间远大于这10%的内存空间时,也就是Survivor空间不够用时,需要额外的空间来担保,通常是将这些对象转移到老年代。

对于老年代来说,大部分对象都处在存活状态。同时,如果一个大对象要在该区域进行分配,而内存空间又不足,那么在没有外部内存空间担保的情况下,就必须选用标记-清除或者标记-整理算法来进行垃圾回收了。

 

总而言之,分代收集只是根据对象生存周期的不同来选择不同的算法,其本身并没有任何新思想。

 

 

5. 增量收集算法

以上所述的算法,都存在一个缺点:在进行垃圾回首时需要暂停当前应用的执行,也就是这时候的垃圾回收线程不能和应用线程同时运行。

如果我们想做到“在不打断同学们看书的情况下,图书管理员就可以收集没有被看的书”,这也是增量收集算法的目标,即在不中断应用线程的状态下垃圾回收线程也能进行垃圾回收。

但是这里需要面对的问题是:垃圾回收线程在标记阶段标记好了,还没来的及清除时,当前应用线程进行内存操作,以至于清除阶段无法正确开展,类似的情况是:图书管理员刚标记了《JAVA核心技术》这本书已经没有人看了,等标记完后,却发现这本书已经有人在看了。

 


哪几个常见的垃圾回收器

原文地址

 

1. Serial 收集器(新生代)

  • Serial 即串行的意思,也就是说它以串行的方式执行,它是单线程的收集器,只会使用一个线程进行垃圾收集工作,GC 线程工作时,其它所有线程都将停止工作。

  • 使用复制算法收集新生代垃圾。

  • 它的优点是简单高效,在单个 CPU 环境下,由于没有线程交互的开销,因此拥有最高的单线程收集效率,所以,它是 Client 场景下的默认新生代收集器。

  • 显式的使用该垃圾收集器作为新生代垃圾收集器的方式:-XX:+UseSerialGC

 

2. ParNew 收集器(新生代)

  • 就是 Serial 收集器的多线程版本,但要注意一点,ParNew 在单核环境下是不如 Serial 的,在多核的条件下才有优势。

  • 使用复制算法收集新生代垃圾。

  • Server 场景下默认的新生代收集器,除了性能原因外,主要是因为除了 Serial 收集器,只有它能与 CMS 收集器配合使用。

  • 显式的使用该垃圾收集器作为新生代垃圾收集器的方式:-XX:+UseParNewGC

3. Parallel Scavenge 收集器(新生代)

  • 同样是多线程的收集器,其它收集器目标是尽可能缩短垃圾收集时用户线程的停顿时间,而它的目标是提高吞吐量(吞吐量 = 运行用户程序的时间 / (运行用户程序的时间 + 垃圾收集的时间))。

  • 停顿时间越短就越适合需要与用户交互的程序,良好的响应速度能提升用户体验。而高吞吐量则可以高效率地利用 CPU 时间,尽快完成程序的运算任务,适合在后台运算而不需要太多交互的任务。

  • 使用复制算法收集新生代垃圾。

  • 显式的使用该垃圾收集器作为新生代垃圾收集器的方式:-XX:+UseParallelGC

 

Scavenge[ˈskævɪndʒ]

4. Serial Old 收集器(老年代)

  • Serial 收集器的老年代版本,Client 场景下默认的老年代垃圾收集器。

  • 使用标记-整理算法收集老年代垃圾。

  • 显式的使用该垃圾收集器作为老年代垃圾收集器的方式:-XX:+UseSerialOldGC

5. Parallel Old 收集器(老年代)

  • Parallel Scavenge 收集器的老年代版本。

  • 在注重吞吐量的场景下,可以采用 Parallel Scavenge + Parallel Old 的组合。

  • 使用标记-整理算法收集老年代垃圾。

  • 显式的使用该垃圾收集器作为老年代垃圾收集器的方式:-XX:+UseParallelOldGC

6. CMS 收集器(老年代)

  • CMS(Concurrent Mark Sweep),收集器几乎占据着 JVM 老年代收集器的半壁江山,它划时代的意义就在于垃圾回收线程几乎能做到与用户线程同时工作。

  • 使用标记-清除算法收集老年代垃圾。

 

工作流程主要有如下 4 个步骤:

  • 初始标记: 仅仅只是标记一下 GC Roots 能直接关联到的对象,速度很快,需要停顿(Stop-the-world)

  • 并发标记: 进行 GC Roots Tracing 的过程,它在整个回收过程中耗时最长,不需要停顿

  • 重新标记: 为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,需要停顿(Stop-the-world)

  • 并发清除: 清理垃圾,不需要停顿

在整个过程中耗时最长的并发标记和并发清除过程中,收集器线程都可以与用户线程一起工作,不需要进行停顿。

 

但 CMS 收集器也有如下缺点:

  • 吞吐量低

  • 无法处理浮动垃圾

  • 标记 - 清除算法带来的内存空间碎片问题

 

显式的使用该垃圾收集器作为老年代垃圾收集器的方式:-XX:+UseConcMarkSweepGC

7. G1 收集器(新生代 + 老年代)

  • G1(Garbage-First),它是一款面向服务端应用的垃圾收集器,在多 CPU 和大内存的场景下有很好的性能。HotSpot 开发团队赋予它的使命是未来可以替换掉 CMS 收集器。

  • 使用复制 + 标记 - 整理算法收集新生代和老年代垃圾。

  • G1 把堆划分成多个大小相等的独立区域(Region),新生代和老年代不再物理隔离。

  • 显式的使用该垃圾收集器作为老年代垃圾收集器的方式:-XX:+UseG1GC

 

如何判断一个对象是否应该被回收?

这就是所谓的对象存活性判断,常用的方法有两种:

  • 引用计数法

  • 对象可达性分析

 

 

由于引用计数法存在互相引用导致无法进行GC的问题,所以目前JVM虚拟机多使用对象可达性分析算法.

 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值