深入理解java虚拟机(二)jvm的垃圾收集机制

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

                     (1)引用计数算法

                                   给对象添加一个引用计数器,每当有一个地方引用它时,计数器值加一;当引用失效时,计数器减一。

                                   在任何时刻计数器为0的对象是不可能再被使用的。(缺点:循环引用问题  例如obja.instance=objb  objb.instacnce=objb 这两个对象相互引用但不可能再被访问,但不会被回收。)

                    (2)可达性分析算法

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

                  在Java语言中,可作为GC Roots的对象包括下面几种:

               a) 虚拟机栈中引用的对象(栈帧中的本地变量表);

               b) 方法区中类静态属性引用的对象;

               c) 方法区中常量引用的对象;

               d) 本地方法栈中JNI(Native方法)引用的对象。

2.垃圾收集算法:

               (1)标记-清除算法:

                             算法分为标记和清除两个阶段,首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。                      缺点: 1.标记和清除两个过程的效率都不高

                                2.标记清除过后会产生大量的内存碎片。

       

                  (2)复制算法:

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

                      

                          新生代采取复制算法,在Minor GC之前,to survivor区域保持清空,对象保存在Eden和from survivor区,minor GC运行时,Eden中的幸存对象会被复制到to Survivor(同时对象年龄会增加1)。而from survivor区中的幸存对象会考虑对象年龄,如果年龄没达到阈值,对象依然复制到to survivor中。如果对象达到阈值那么将被移到老年代。复制阶段完成后,Eden和From幸存区中只保存死对象,可以视为清空。如果在复制过程中to幸存区被填满了,剩余的对象将被放到老年代(分配担保)。最后,From survivor和to survivor会调换一下名字,下次Minor GC时,To survivor变为From Survivor。

                         一般 Eden:Survivo=8:1        对于一些较大的对象直接进入老年代。
              

            (3)标记-整理算法                         

             标记整理算法适用于对象存活率较高的场景(适用于老年代),标记过程和标记-清除算法一样,但后续不是直接对可回收对象进行清理,而是让所有存活的对象向一端移动,然后清理掉边界以外的对象。

         (4)分代收集算法:

              现代商用虚拟机基本都采用分代收集算法来进行垃圾回收。

              根据对象的生命周期的不同将内存划分为几块,然后根据各块的特点采用最适当的收集算法。大批对象死去、少量对象存活的(新生代),使用复制算法,复制成本低;对象存活率高、没有额外空间进行分配担保的(老年代),采用标记-清理算法或者标记-整理算法。

3.四种引用状态

          我们希望能够描述这一类对象:当内存空间还足够时,则能够保存在内存之中;如果内存空间进行垃圾回收后还是十分紧张,那么可以抛弃这些对象。

   (1)强引用:强引用就是指在程序代码中普遍存在的,只要强引用还存在,垃圾回收器就永远不会回收掉的对象。

   (2)软引用:软引用是用来描述一些还有用但并非必须的对象。在系统发生内存溢出之前,会把这些对象列进回收范围进行回收,如果这次回收还没有足够的内存,则抛出内存溢出异常(SoftReference实现)

   (3)弱引用:被弱引用关联的对象只能生存到下一次垃圾收集发生之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。

   (4)虚引用:又称幽灵引用或幻影引用,是最弱的一种引用。

4.新生代、老年代、永久带

  新生代

主要是用来存放新生的对象。一般占据堆的1/3空间。由于频繁创建对象,所以新生代会频繁触发MinorGC进行垃圾回收。

新生代又分为 Eden区、ServivorFrom、ServivorTo三个区。

  • Eden区:Java新对象的出生地(如果新创建的对象占用内存很大,则直接分配到老年代)。当Eden区内存不够的时候就会触发MinorGC,对新生代区进行一次垃圾回收。
  • ServivorTo:保留了一次MinorGC过程中的幸存者。
  • ServivorFrom:上一次GC的幸存者,作为这一次GC的被扫描者。

当JVM无法为新建对象分配内存空间的时候(Eden满了),Minor GC被触发。因此新生代空间占用率越高,Minor GC越频繁。

MinorGC的过程:采用复制算法。

老年代

    老年代的对象比较稳定,所以MajorGC不会频繁执行。

在进行MajorGC前一般都先进行了一次MinorGC,使得有新生代的对象晋身入老年代,导致空间不够用时才触发。当无法找到足够大的连续空间分配给新创建的较大对象时也会提前触发一次MajorGC进行垃圾回收腾出空间。

MajorGC采用标记—清除算法。

永久代

      指内存的永久保存区域,主要存放Class和Meta(元数据)的信息。

Class在被加载的时候被放入永久区域。它和和存放实例的区域不同,GC不会在主程序运行期对永久区域进行清理。所以这也导致了永久代的区域会随着加载的Class的增多而胀满,最终抛出OOM异常。

在Java8中,永久代已经被移除,被一个称为“元数据区”(元空间)的区域所取代。

  • Major GC和Full GC区别
  • Full GC:收集young gen、old gen、perm gen
  • Major GC:有时又叫old gc,只收集old gen

5.回收方法区(永久代):

     主要回收:1.废弃常量 2.无用的类

     回收废弃常量:在当前系统中没有一个对象引用该字面量

     回收无用的类需要满足三个条件:

                     1.该类所有的实例都已经被回收,在堆中不存在该类的任何实例

                     2.加载该类的ClassLoader已经被回收

                     3.该类对应java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。

6.其它概念:

                  1.Stop The World:从GC Roots进行可达性分析,为了保存一致性,停顿所有的java执行线程

                  2.准确性GC:虚拟机可以知道内存中某个位置的数据具体是什么类型

                 3.安全点:SafePoint 即程序执行时并非在所有地方都能停顿下来,只要安全点才能停顿。

                 4.抢先式中断和主动式中断:抢先式首先把所有的线程全部中断,如果发现有线程不在安全点则回复线程

                    主动式中断:通过设置标志,线程执行时轮询标志,发现标志则自己中断

7.常见面试题:

     1.GC是什么? 为什么要有GC?

        GC时垃圾回收的意思,内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定或崩溃,java提供的GC功能,可以自动检测对象是否超过作用域从而到达自动回收内存的目的

2.存在循环引用怎么做?

   HotSpot虚拟机中利用可达性算法可以解决这个问题,可达性算法通过一系列称为“GC roots”的对象作为起点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GCroots没有任何引用链相连,则这证明该对象不可用。

3.怎么预防full gc

  以下情况会出现full gc

    (1)老年代空间不足:老年代只有在新生代对象转入以及创建为大对象、大数组才会出现不足的情况

              预防:调优时应尽量做到让对象在minor GC 阶段被回收、让对象在新生代多活一段时间以及不要创建过大的对象以及数组。

   (2)永久代空间满 

             预防:可采用增大Perm  Gen空间或者转为使用CMS GC

    (3)GMS GC时出现promotion failed 和concurrent mode failure

             promotionfailed是在进行Minor GC时,survivor space放不下、对象只能放入旧生代,而此时旧生代也放不下造成的;concurrent mode failure是在执行CMS GC的过程中同时有对象要放入旧生代,而此时旧生代空间不足造成的。

              预防:增大survivorspace 老年代空间或者调低触发并发GC的比率

4.年轻带为什么有两个Survivor,解决什么问题

https://blog.csdn.net/antony9118/article/details/51425581

5.垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收?

基本原理:对于GC来说,当程序员创建对象时,GC就开始监控这个对象的地址、大小以及使用情况。通常,GC采用有向图的

方式记录和管理堆中的所有对象。通过这种方来确定哪些对象时可达的,哪些对象不可达。当GC确定一些对象不可达,GC就会责任回收这些内存空间。

是否可以马上回收:可以

通知回收:手动执行 System.gc()

6.

猜你喜欢

转载自blog.csdn.net/weixin_42173193/article/details/84956098