快捷搜索:  汽车  科技

怎么查看jvm使用的垃圾收集器(最全的JVM面试知识点)

怎么查看jvm使用的垃圾收集器(最全的JVM面试知识点)堆中几乎放着所有的对象实例,对堆垃圾回收前的第一步就是要判断那些对象已经死亡(即不能再被任何途径使用的对象)。小结对象回收垃圾收集算法垃圾收集器

快,关注米兜Java,一起涨姿势~

怎么查看jvm使用的垃圾收集器(最全的JVM面试知识点)(1)

热点推荐
  • 终于有人将 MySQL 索引讲清楚了
  • 最全的 JVM 面试知识点(一):运行时数据区
  • 最全的 JVM 面试知识点(二):JVM 类加载
  • 最全的 JVM 面试知识点(三):垃圾收集——Java中的引用

最全的 JVM 面试知识点(四):垃圾收集

01前言

前面讲述了JVM中运行时数据区、JVM类加载及垃圾收集中的Java的引用,具体文章大伙可以查询米兜博客-基础知识系列文章。本章主要对垃圾收集收一下尾巴。

本文的主要内容:

对象回收

  • 引用计数法
  • 可达性分析算法

垃圾收集算法

  • 标记-清除算法
  • 标记-整理算法
  • 复制算法
  • 分代收集算法

垃圾收集器

小结

02对象回收

堆中几乎放着所有的对象实例,对堆垃圾回收前的第一步就是要判断那些对象已经死亡(即不能再被任何途径使用的对象)。

引用计数法

给对象中添加一个引用计数器,每当有一个地方引用它,计数器就加 1;当引用失效,计数器就减 1;任何时候计数器为 0 的对象就是不可能再被使用的。

引用计数法可以很快的执行,交织在程序运行中。对程序需要不被长时间打断的实时环境比较有利。实现简单,效率高,但是目前主流的虚拟机中并没有选择这个算法来管理内存,其最主要的原因是它很难解决对象之间相互循环引用的问题。如父对象有一个对子对象的引用,子对象反过来引用父对象。这样,他们的引用计数永远不可能为 0。

可达性分析算法

这个算法的基本思想就是通过一系列的称为 GC Roots 的对象作为起点,从这些节点开始向下搜索,节点所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连的话,则证明此对象是不可用的。

怎么查看jvm使用的垃圾收集器(最全的JVM面试知识点)(2)

在 Java 中哪些对象可以成为 GC Root?

  • 虚拟机栈(栈帧中的本地变量表)中的引用对象
  • 方法区中的类静态属性引用的对象
  • 方法区中的常量引用对象
  • 本地方法栈中JNI(即Native方法)的引用对象
03垃圾收集算法

常用的垃圾收集算法有:标记-清除、标记-整理、复制和分代收集算法。下面依次介绍这几种垃圾收集算法。

标记-清除算法

首先标记出需要回收的对象,在标记完成后统一回收掉所有的被标记对象。

怎么查看jvm使用的垃圾收集器(最全的JVM面试知识点)(3)

缺点:效率问题和空间问题(标记清除后会产生大量的不连续内存碎片,内存碎片过多可能会导致程序需要分配较大对象时找不到足够大的连续内存空间而不得不提前触发另一次垃圾回收动作)

标记-整理算法

标记-整理 算法采用 标记-清除 算法一样的方式进行对象的标记,但在清除时不同,在回收不存活的对象占用的空间后,会将所有的存活对象往左端空闲空间移动,并更新对应的指针。标记-整理算法是在标记-清除算法的基础上,又进行了对象的移动,因此成本更高,但是却解决了内存碎片的问题。

怎么查看jvm使用的垃圾收集器(最全的JVM面试知识点)(4)

复制算法

将内存划分为大小相等的两块,每次只使用其中的一块。当这块内存用完了,就将还存活的对象复制到另一块内存上,然后把已使用过的内存空间一次清理掉。

复制算法的提出是为了克服句柄的开销和解决内存碎片的问题。每次只对其中一块进行GC,不用考虑内存碎片的问题,并且实现简单,运行高效。缺点是内存缩小了一半。

怎么查看jvm使用的垃圾收集器(最全的JVM面试知识点)(5)

分代收集算法

分代收集算法是目前大部分JVM的垃圾收集器采用的算法。它的核心思想是根据对象存活的生命周期将内存划分为若干个不同的区域。一般情况下将堆区划分为老年代(Tenured Generation)和新生代(Young Generation),在堆区之外还有一个代就是永久代(Permanet Generation)。老年代的特点是每次垃圾收集时只有少量对象需要被回收,而新生代的特点是每次垃圾回收时都有大量的对象需要被回收,那么就可以根据不同代的特点采取最适合的收集算法。

怎么查看jvm使用的垃圾收集器(最全的JVM面试知识点)(6)

年轻代(Young Generation)的回收算法

所有新生成的对象首先都是放在年轻代的。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。

新生代内存按照 8:1:1 的比例分为一个 Eden 区和两个 survivor(survivor0 survivor1) 区。一个E den 区,两个 Survivor 区(一般而言)。大部分对象在 Eden 区中生成。回收时先将 Eden 区存活对象复制到一个 survivor0 区,然后清空 Eden 区,当这个 survivor0 区也存放满了时,则将 Eden 区和 survivor0 区存活对象复制到另一个 survivor1 区,然后清空 Eden 和这个 survivor0 区,此时 survivor0 区是空的,然后将 survivor0 区和 survivor1 区交换,即保持 survivor1 区为空, 如此往复。

当 survivor1 区不足以存放 Eden 和 survivor0 的存活对象时,就将存活对象直接存放到老年代。若是老年代也满了就会触发一次 Full GC,也就是新生代、老年代都进行回收。

新生代发生的 GC 也叫做 Minor GC,Minor GC 发生频率比较高(不一定等 Eden 区满了才触发)。

年老代(Old Generation)的回收算法

在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。

内存比新生代也大很多(大概比例是 1:2),当老年代内存满时触发 Major GC 即 Full GC,Full GC 发生频率比较低,老年代对象存活时间比较长,存活率标记高。

持久代(Permanent Generation)的回收算法

用于存放静态文件,如 Java 类、方法等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些 class,例如 Hibernate 等,在这种时候需要设置一个比较大的持久代空间来存放这些运行过程中新增的类。持久代也称方法区,方法区存储内容是否需要回收的判断不一样。方法区主要回收的内容有:废弃常量和无用的类。对于废弃常量也可通过引用的可达性来判断,但是对于无用的类则需要同时满足下面 3 个条件:

  • 该类所有的实例都已经被回收,也就是 Java 堆中不存在该类的任何实例;
  • 加载该类的 ClassLoader 已经被回收;
  • 该类对应的 java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
04垃圾收集器

不同的垃圾回收器,适用于不同的场景。常用的垃圾回收器:

  • 串行(Serial)回收器是单线程的一个回收器,简单、易实现、效率高。
  • 并行(ParNew)回收器是Serial的多线程版,可以充分的利用CPU资源,减少回收的时间。
  • 吞吐量优先(Parallel Scavenge)回收器,侧重于吞吐量的控制。
  • 并发标记清除(CMS,Concurrent Mark Sweep)回收器是一种以获取最短回收停顿时间为目标的回收器,该回收器是基于 标记-清除 算法实现的。
05小结

本文讲了 JVM 垃圾收集中对象死亡的判断算法:引用计数法和可达性分析。最后介绍了几种常见的垃圾收集算法。关于具体的垃圾回收器将在下一篇文章具体介绍。

END!

米兜Java

请留下你指尖的温度

让太阳拥抱你

记得这是一个有温度的头条号

print_r('点个好看吧!');

var_dump('点个好看吧!');

NSLog(@"点个好看吧!");

System.out.println("点个好看吧!");

console.log("点个好看吧!");

print("点个好看吧!");

printf("点个好看吧! ");

cout << "点个好看吧!" << endl;

Console.WriteLine("点个好看吧!");

fmt.Println("点个好看吧!");

Response.Write("点个好看吧!");

alert("点个好看吧!")

echo"点个好看吧!"

猜您喜欢: