Loading

JVM垃圾回收

Java GC
java堆是垃圾收集器管理的主要区域,所以被称为GC堆,所以Java堆可以细分为新生代,老生代,新生代再分为Eden空间,from survive区和to survive区,这样更细的分是因为更好的回收内存。
大部分情况,对象都会首先在Eden区域分配,随着对象的创建,Eded剩余内存空间越来越少,就会触发Minor GC,于是Eden
的存活对象会放入From Survivor空间,Minor GC后,新对象依然会往Eden分配,Eden剩余内存空间越来越少,又会出发Minor GC,
于是Eden和from survivor的存活对象会放入To Survivor空间。长期存活的对象将进入老年代,如果一个对象A,经历了15次Minor GC
还存活在Survivor空间中,那么就会转移到老年代,这个15可以设置为默认为15.

 

1.如何判断对象是否死亡?

1.可达性分析算法,对象到GC root 没有引用链相连,说明是可以回收的
2.引用计数法算法,给对象添加一个引用计数器,每当有一个地方引用对象时,计数器加1,当引用失效的时候,引用计数器的值减1,当引用计数器为0,就可以回收

那么什么是GC Root?有哪些GC Root?

     定义一系列的GC Root 为起点,从起点开始向下开始搜索,搜索走过的路径成为引用链,当一个对象到GC Root没有任何引用链相连的话,则对象是可以被回收的。

     可以作为GC Root的对象包括:

         1.栈中引用的对象

         2.静态变量,常量引用的对象

         3.本地方法栈native方法引用的对象

  

对象可以被回收,就代表一定会被回收吗?

      即使在可达性分析法中不可达的对象,也并非是“非死不可的‘。要真正宣布一个对象死亡,至少要经历两次标记过程,当对象没有覆盖finalice方法,或finalice方法已经被虚拟机调用过时,虚拟机将这两种情况没有必要执行。

判断一个对象应该被回收

    1.该对象没有与GC Roots相连

    2.要真正宣布一个对象死亡,至少要经历两次标记过程,当对象没有覆盖finalice方法,或finalice方法已经被虚拟机调用过时,虚拟机将这两种情况没有必要执行。

 

 

2.简单的介绍强引用,软引用,弱引用,虚引用(虚引用与软引用和弱引用的区别,使用软引用能带来的好处)

       可达性分析算法除了GC Roots,还有一个引用,引用分为:

                强引用:只要强引用还在,垃圾收集器永远不会回收被引用的对象

                软引用:在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之中进行第二次回收。如果这次回收还没有足够的内存,才会抛出内存溢出异常

                弱引用:被弱引用关联的对象只能存活到下一次垃圾收集发生之前

                虚引用:为对象设置虚引用关联的唯一目的就是在这个对象被收集器回收时收到一个系统通知

3.如何判断一个常量是废弃常量 (回收方法区)

      运行时常量池主要回收的时废弃的常量,那么我们如何判断一个常量时废弃常量呢?

               jdk1.7之前运行时常量池逻辑包含字符串常量池存放在方法区,此时hotspot虚拟机对方法区的实现为永久代

               jdk1.7,字符串常量池从方法区拿出来放到了堆中,运行时常量池剩下的东西还在方法区

               jdk1.8  hotspot移除了永久代用空间代替,这时候字符串常量池还在堆中,运行时常量池还在方法去,只不过方法区的实现从永久代变成了元空间。

      假如在字符串常量池中存在字符串“abc”,如果当前没有任何String对象引用该字符串常量的话,就说明“abc”就是废弃常量

4.如何判断一个类是无用的类(回收方法区)

方法区主要回收的是无用的类。类需要同时满足下面3个条件才能算是“无用的类”:

           该类所有的实例都已经被回收

           加载该类ClassLoader已经被回收

           该类对应的java.lang.class对象没有在任何地方被引用。

5.垃圾收集有哪些算法,各自的特点?

标记-清除算法:先标记哪些对象是存活的,哪些对象是可以回收的,然后在把标记为可回收的对象清除掉

标记-复制算法:为了解决效率问题,它可以将内存分为大小相同的两块,每次使用其中的一块。当这一块的内存使用完后,就将还存活的对象复制到另一块,然后再把使用的空间一次清理掉。这样就能使每次的内存回收都是对内存区间的一半进行回收。

标记-整理算法:标记-整理算法都是先标记哪些对象存货,哪些对象可以回收,不同的是他并没有直接清理可回收的对象,而是先把存活的对象进行移动,这样存活的对象就紧密的靠在一起,最后才把垃圾回收掉。

分代收集算法:一般将java堆分为新生代和老生代,这样我们就可以根据各个年代的特点选择合适的垃圾收集算法。

          比如在新生代中,每次收集都会有大量对象死去,所以我们可以选择标记-复制算法,只需要付出少量对象的复制成本就可以完成每次垃圾收集。而老生代存活的几率是比较高的,而且,没有额外的空间对他进行分配担保,所以我们必须选择标记-清楚或标记-整理算法进行垃圾收集

6.HotSpot为什么要分为新生代和老生代?

一般将java堆分为新生代和老生代,这样我们就可以根据各个年代的特点选择合适的垃圾收集算法。

          比如在新生代中,每次收集都会有大量对象死去,所以我们可以选择标记-复制算法,只需要付出少量对象的复制成本就可以完成每次垃圾收集。而老生代存活的几率是比较高的,而且,没有额外的空间对他进行分配担保,所以我们必须选择标记-清楚或标记-整理算法进行垃圾收集

 

7.常见的垃圾回收器有哪些?

 

年轻代的垃圾收集器包含有Serial、ParNew、Parallell,⽼年代则包括Serial Old⽼年代版本、CMS、 Parallel Old⽼年代版本和JDK11中的船新的G1收集器。

Serial:单线程版本收集器,进⾏垃圾回收的时候会STW(Stop The World),也就是进⾏垃圾回收的 时候其他的⼯作线程都必须暂停

ParNew:Serial的多线程版本,⽤于和CMS配合使⽤

Parallel Scavenge:可以并⾏收集的多线程垃圾收集器,关注系统的吞吐量

Serial Old:Serial的⽼年代版本,也是单线程 Parallel Old:Parallel Scavenge的⽼年代版本 CMS(Concurrent Mark Sweep):CMS收集器是以获取最短停顿时间为⽬标的收集器,相对于其他 的收集器STW的时间更短暂,可以并⾏收集是他的特点,同时他基于标记-清除算法,整个GC的过程分 为4步。

   1. 初始标记:标记GC ROOT能关联到的对象,需要STW

   2. 并发标记:从GCRoots的直接关联对象开始遍历整个对象图的过程,不需要STW

   3. 重新标记:为了修正并发标记期间,因⽤户程序继续运作⽽导致标记产⽣改变的标记,需要STW

   4. 并发清除:清理删除掉标记阶段判断的已经死亡的对象,不需要STW

从整个过程来看,并发标记和并发清除的耗时最⻓,但是不需要停⽌⽤户线程,⽽初始标记和重新标记 的耗时较短,但是需要停⽌⽤户线程,总体⽽⾔,整个过程造成的停顿时间较短,⼤部分时候是可以和 ⽤户线程⼀起⼯作的。

G1(Garbage First):G1收集器是JDK9的默认垃圾收集器,⽽且不再区分年轻代和⽼年代进⾏回收。

 

8.什么时候会触发YGC和FGC?对象什么时候会进入老年代?

      当一个新的对象来申请内存空间的时候,如果Eden区无法满足内存分配需求,则触发YGC(Minor GC),于是Eden区的存活对象会放入survivor空间,如果YGC之后还是没有足够内存空间,则直接进入老年代分配,如果老年代也无法分配空间,触发FGC,FGC之后还是放不下,则报OOM异常。

 

9.Minor GC 和Full GC 有什么不同?

Minor GC 只对新生代进行垃圾收集

Full GC收集整个java堆和方法区

 

JVM的永久代中会发生垃圾回收吗?

      垃圾回收不会发生在永久代,如果永久代满了或者是超过了临界值,会触发完全垃圾回收(Full GC)。

 

posted @ 2022-03-17 21:26  远乡人  阅读(164)  评论(0编辑  收藏  举报