JVM----垃圾回收机制

垃圾回收过程

  任何一种垃圾回收算法一般要做两件基本事情:

  1. 发现无用的对象

  2. 回收无用对象占用的内存空间。

  垃圾回收机制保证可以将“无用的对象”进行回收。无用的对象指的就是没有任何变量引用该对象。Java的垃圾回收器通过相关算法发现无用对象,并进行清除和整理。

如何判断对象可以被回收

  1. 引用计数法

  堆中每个对象都有一个引用计数。被引用一次,计数加1. 被引用变量值变为null,则计数减1,直到计数为0,则表示变成无用对象。优点是算法简单,缺点是“循环引用的无用对象”无法别识别。

  循环引用示例(s1和s2互相引用对方,导致他们引用计数不为0,但是实际已经无用,但无法被识别。

public class Student {
    String name;
    Student friend;
     
    public static void main(String[] args) {
        Student s1 = new Student();
        Student s2 = new Student();
         
        s1.friend = s2;
        s2.friend = s1;        
        s1 = null;
        s2 = null;
    }
}

  2. 引用可达法(根搜索算法)

  程序把所有的引用关系看作一张图,从一个节点GC ROOT开始,寻找对应的引用节点,找到这个节点以后,继续寻找这个节点的引用节点,当所有的引用节点寻找完毕之后,剩余的节点则被认为是没有被引用到的节点,即无用的节点。

 

垃圾收集算法

 

 

                        

 

标记-清除算法

  直接在原来堆上将不可用对象清空(不实用)

  算法分为“标记”和“清除”阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。它是最基础的收集算法,效率也很高,但是会带来两个明显的问题: 
  1. 效率问题 
  2. 空间问题(标记清除后会产生大量不连续的碎片,会造成即使有空间也不能存放过大对象)
 

               

复制算法 

  参考年轻代将存活对象复制到Survivor区的,年轻代使用复制算法。

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

标记-整理算法 

  根据老年代的特点特出的一种标记算法,标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象回收,而是让所有存活的对象向一段移动,然后直接清理掉端边界以外的内存。
                     
 
 

分代收集算法 

  当前虚拟机的垃圾收集都采用分代收集算法,这种算法没有什么新的思想,只是根据对象存活周期的不同将内存分为几块。一般将java堆分为新生代和老年代,这样我们就可以根据各个年代的特点选择合适的垃圾收集算法。比如在新生代中,每次收集都会有大量对象(近99%)死去,所以可以选择复制算法,只需要付出少量对象的复制成本就可以完成每次垃圾收集。而老年代的对象存活几率是比较高的,而且没有额外的空间对它进行分配担保,所以我们必须选择“标记-清除”或“标记-整理”算法进行垃圾收集。注意,“标记-清除”或“标记-整理”算法会比复制算法慢10倍以上

 

垃圾收集器

 

 

通用的分代垃圾回收机制

  分代垃圾回收机制,是基于这样一个事实:不同的对象的生命周期是不一样的。因此,不同生命周期的对象可以采取不同的回收算法,以便提高回收效率。我们将对象分为三种状态:年轻代、年老代、持久代。JVM将堆内存划分为 Eden、Survivor 和 Tenured/Old 空间。

  1. 年轻代

  所有新生成的对象首先都是放在Eden区。 年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象,对应的是Minor GC,每次 Minor GC 会清理年轻代的内存,算法采用效率较高的复制算法,频繁的操作,但是会浪费内存空间。当“年轻代”区域存放满对象后,就将对象存放到年老代区域。

  2. 年老代

  1、在年轻代中经历了N(默认15)次垃圾回收后仍然存活的对象,就会被放到年老代中。

  2、年轻代放不下的对象也会放到年老代。

  3、minor GC之后,判断suvivor区的对象,比如有年龄1对象,年龄2对象,年龄3对象,年龄4对象,年龄1+年龄2+年龄3>50%suvivor,就吧年龄3及以上的年龄对象全部放到年老区。目的:将可能长期存活的对象尽早放到年老代。

  大对象会直接放到年老代,配置-XX:PretenureSizeThreshold=1024*10(单位字节)

  因此,可以认为年老代中存放的都是一些生命周期较长的对象。年老代对象越来越多,我们就需要启动Major GC和Full GC(全量回收),来一次大扫除,全面清理年轻代区域和年老代区域。

  3. 持久代(不参与垃圾回收)

  用于存放静态文件,如Java类、方法等。垃圾回收对持久代没有显著影响。

  Minor GC:

  用于清理年轻代区域。Eden区满了就会触发一次Minor GC。清理无用对象,将有用对象复制到“Survivor1”、“Survivor2”区中(这两个区,大小空间也相同,同一时刻Survivor1和Survivor2只有一个在用,一个为空)

  Major GC:

  用于清理老年代区域。

  Full GC:

  用于清理年轻代、年老代区域。 成本较高,会对系统性能产生影响。

垃圾回收过程:

minorGC

    1、新创建的对象,绝大多数都会存储在Eden中,

    2、当Eden满了(达到一定比例)不能创建新对象,则触发垃圾回收(GC),将无用对象清理掉,

           然后剩余对象复制到某个Survivor中,如S1,同时清空Eden区

    3、当Eden区再次满了,会将S1和Eden区中的不能清空的对象存到另外一个Survivor中,保证Eden和S1,均被清空。

    4、重复多次(默认15次,这个次数保存在对象头中)Survivor中没有被清理的对象,则会复制到老年代Old(Tenured)区中,

FullGC

  1、当Old区满了,则会触发一个一次完整地垃圾回收(FullGC)

  2、(担保机制)年轻代每次minor gc之前JVM都会计算下老年代剩余可用空间,如果这个可用空间小于年轻代里现有的所有对象大小之和(包括垃圾对象) ,就会看一个“-XX:-HandlePromotionFailure”(jdk1.8默认就设置了)的参数是否设置了,如果有这个参数,就会看看老年代的可用内存大小,是否大于之前每一次minor gc后进入老年代的对象的平均大小。 如果上一步结果是小于或者之前说的参数没有设置,那么就会触发一次Full gc,对老年代和年轻代一起回收一次垃圾,如果回收完还是没有足够空间存放新的对象就会发生"OOM" 当然,如果minor gc之后剩余存活的需要挪动到老年代的对象大小还是大于老 年代可用空间,那么也会触发full gc,full gc完之后如果还是没用空间放minor gc之后的存活对象,则也会发生“OOM”  

                   

 

 

finalize方法

  注意:当程序中写入代码 System.gc();不代表会立刻启动垃圾回收机制。finalize方法,是Java提供给程序员用来释放对象或资源的方法,但是尽量少用。

  引用可达法,不可达的对象并不一定会马上回收掉,他们处于缓刑阶段。要真正宣告一个对象死亡,至少要经历再次标记过程。

1. 第一次标记并进行一次筛选。 
  筛选的条件是此对象是否有必要执行finalize()方法。 当对象没有覆盖finalize方法,对象将直接被回收。 
2. 第二次标记 
  如果这个对象覆盖了finalize方法,finalize方法是对象脱逃死亡命运的最后一次机会,如果对象要在finalize()中成功拯救自己,只要重新与引用链上的任何的一个对象建立关联即可,譬如把自己赋值给某个类变量或对象的成员变量,那在第二次标记时它将移除出“即将回收”的集合。如果对象这时候还没逃脱,那基本上它就真的被回收了。

 

回收类

  类元信息都在方法区,无用的类什么时候回收

  • 该类所有的实例都已经被回收,也就是 Java 堆中不存在该类的任何实例。(对象头有指针指向类元信息)
  • 加载该类的 ClassLoader 已经被回收。 
  • 该类对应的 java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。

 

full GC

  如果old区的内存太大了,而且如果频繁进行FullGC,系统会异常的卡。这个是PS PO GC的缺点,所以需要换GC。应该换GI

内存泄露和内存溢出

  内存泄露是指程序在申请内存时,无法释放已经申请的内存空间,这就造成了内存泄露,一次内存泄露似乎不会有大的影响,但是内存泄露堆积的后果就是内存溢出。

开发中容易造成内存泄露的操作

  参考:https://www.sxt.cn/Java_jQuery_in_action/The_operation_of_memory_leakage_in_development.html

  参考:https://www.sxt.cn/Java_jQuery_in_action/The_garbage_collection_mechanism.html

https://www.cnblogs.com/shengulong/p/8513652.html

 

posted @ 2019-07-28 19:41  小名的同学  阅读(163)  评论(0编辑  收藏  举报