垃圾回收

四、 JVM GC的一整套(算法、分区、判断方法、GC器);

  1. 垃圾:当一个对象没有被指针引用的时候,他就是垃圾。
  2. 垃圾回收区域
    java堆和方法区


    image.png
  3. 判断一个对象是否垃圾常用的有两种办法:引用计数和可达分析。
  • 引用计数:每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时可以回收。此方法简单,但是无法解决对象互相循环引用的的问题。
  • 可达分析:从GC roots开始向下搜索,搜索所经过的路径称为引用链。当一个对象到一个GC Roots没有任何引用链相连时,证明此对象是不可用的,可以回收。
    在Java语言中,GC Roots包括:
    虚拟机栈中引用的对象。
    方法区中类静态属性实体引用的对象。
    方法区中常量引用的对象。
    本地方法栈中JNI引用的对象。
  1. 什么时候触发GC?
  • 程序调用System.gc时
  • 系统自身来决定GC触发的时机(根据Eden区和From Space区的内存大小来决定。当内存大小不足时,则会启动GC线程并停止应用线程)
  1. GC算法:GC常用算法有:标记-清除算法,标记-压缩算法,复制算法,分代收集算法。
  • 标记-清除算法:为每个对象存储一个标记位,记录对象的状态(活着或者是死亡)。分为两个阶段:
    一个是标记阶段,这个阶段内,为每个对象更新标记位,检查对象是否死亡;
    第二个阶段是清除阶段,该阶段对死亡对象进行清除,执行GC操作。
    // 优缺点图示

  • 标记-压缩(标记-整理)算法:是标记清除的一个改进版。
    同样,在标记阶段,将对象标记为存活和死亡两种状态;
    第二阶段:不会直接对死亡的对象进行清理,而是将所有存活的对象整理一下,放到另一个空间,然后把剩下的所有对象全部清除
    优点:不会产生大量碎片1空间
    缺点:存活对象多,效率低

  • 复制算法:
    该算法将内存平均分为两部分,然后每次只使用其中的一部分,当这部分内存满的时候,将内存中所有存活的对象复制到另一个内存中,然后将之前的清空,只是用这部分内存,循环下去。
    注意:
    这个算法与标记-整理算法的区别在于,该算法不是在同一个区域复制,而是将所有存活的对象复制到另一个区域内。
    优点:实现简单;不产生内存碎片;
    缺点:
    每次运行,总有一半内存是空的,导致可使用的内存空间只有原来的一半。

  • 分代收集算法:
    现在的虚拟机大豆采用这种方式,它根据对象的生存周期,将堆分为新生代(Young)和老年代(Tenure)。在新生代中,由于对象生存周期短,每次回收都有大量对象死去,那么这时就采用复制算法老年代里的对象存活率较高,没有额外的空间进行分配担保,所以可以使用标记清除法或者标记整理法
    具体过程:新生代分为Eden区、Form区、To区

    image.png

    1. 当系统创建一个对象的时候,总是在Eden区操作,当这个区满了,就会触发一次YoungGC,也就是年轻代的垃圾回收。一般来说这时候不是所有对象都没用了,所以就会把还能用的对象复制到From区。


      image.png
    2. 这样Eden区就被清理干净了,可以继续创建对象,当Eden区再次被用完,就在一次触发YoungGC,然后,这次会将Eden区和From区的还在被使用的对象复制到To区。


      image.png
    3. 再下一次YoungGC的时候,则是将Eden区和To区中的还在被使用的对象复制到From区


      image.png
    4. 经历了若干次YoungGC之后,有些对象在From、To之间来回游荡,如果这时候From和To区达到阈值,这次对象就会被复制到老年代。


      image.png
    5. 老年代空间被用完时,就会进行一次Full GC,也就是全量回收。如果FullGC太频繁,会造成系统负担。因此要合理设置年轻代和老年代的大小,尽量减少FullGC的操作

  1. 垃圾收集器:内存回收的具体实现
    1. Serial收集器:串行收集器
  • 串行收集器是最古老、最稳定以及效率高的垃圾收集器。
  • 可能会产生长时间的停顿,只使用一个线程去回收。
  • 新生代:复制算法
  • 老年代:标记-压缩


    image.png
    1. ParNew
  • 新生代并行
  • 老年代串行
  • 回收新生代时并行回收,使用复制算法

2.finalize方法里面不能执行什么样的操作(耗时的操作,会影响GC的时间)

你可能感兴趣的:(垃圾回收)