java学习笔记——JVM垃圾回收

 原文: https://www.jianshu.com/p/a62697f00b85

  https://www.cnblogs.com/aspirant/p/8662690.html

   https://www.cnblogs.com/yw-ah/p/5830458.html

  判断对象是否存活的算法

-    1.引用计数算法

  引用计数算法是垃圾回收的早期策略,堆中每一个对象都有一个引用计数,每有一个地方引用它,计数器就加一,当引用失效时,计数器减一

  优点:执行快,适合程序不允许被长时间打端的场景

  缺点: 如果两个对象互相循环引用,则检测不到

-    2.可达性算法

  从一系列 “GC ROOT“ 节点开始,搜索引用的节点, 搜索过的路径称为引用链,当一个对象到GC ROOT没有引用链相连时,此对象就是不可用的(类似判断连通图?)

  

 

    可作为GC ROOT的对象:

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

      方法区中常量引用的对象

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

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

   PS:在可达性算法中,并不是一次判定后就决定是否回收

    第一次筛选: 在可达性分析后与GC ROOT没有引用链相连时,标记为有必要执行 finalize()方法

    第二次筛选: 在第一次被标记的对象中,如果在其 finalize()方法中 重新与引用链建立了联系,则从”即将回收“集合中移除。

 

-   方法区的垃圾回收

  1. 废弃常量

    废弃常量也是通过引用来判断,即没有任何地方引用的常量会被回收

  2. 类

    无用的类若要进行回收则需要满足以下三个条件:

    (1) 该类所有的实例都已被回收, Java堆中不存在该类的实例

    (2) 加载该类的ClassLoader 已被回收

    (3)该类对应的java.lang.Class 对象没被任何地方引用, 即不会通过反射来访问该类

 

   垃圾收集算法

-  1.复制算法

  过程: 把可用内存按容量分为大小相等的两块,每次都只使用其中的一块,当这块内存用尽后,将存活的对象复制到另一块,然后将此块内存清空

  优点:每次对整个半区进行操作,无需考虑内存碎片等复杂情况,实现简单,运行高效

  缺点: 每次只能使用一半的内存,内存使用率降低

  

 

 -  2.标记-清除算法

  过程:  标记出需要回收的对象,然后统一清除所有被标记的对象

  缺点:   产生的空间碎片太多,清除后有大量不连续的内存碎片,之后若要存储较大对象,因没有足够的连续内存则会触发另一次GC,影响系统性能

 -  3.标记-整理算法

  过程: 标记出需要回收的对象,然后进行整理,使存活的对象都向一端移动,最后直接清理掉边界以外的内存。

  优点: 既没有像复制算法一样浪费50%的空间,也不像标记-清除算法产生内存碎片

  (一般老年代会采用该算法)

  

 分代收集算法

  (1)新生代

      新生代对象存活时间短,只有少量存活,适合使用 复制算法 复制少量存活的对象

    新生代的内存按照8:1:1分为一个eden区和两个survivor区(后文简称S1,S2),对象大部分在eden区生成

    在垃圾回收时,将eden区和S1区存活的对象复制到S2区,然后清空eden和S1,在第二次回收时,S1和S2的角色互换,即保证S1与S2始终一个为空,一个用于缓存 。

    当S1或S2其中一个满了的时候,就将其中的对象转移到老年代。

    或者survivor区未满,但其中的对象经历了一定次数的扫描仍然存活(默认为15次),虚拟机也会将它移动到老年代。

    再或者如果是需要连续内存空间较大的对象,也会直接放入老年代,这样可以避免在survivor区反复复制大对象

    新生代GC (Minor GC)  较为频繁,回收速度块

  (2)老年代

      对象存活率高,存活时间长, 适合使用 标记-清除 或 标记-整理算法,清理掉少数回收对象

    年老代相对于新生代,内存更大,垃圾回收频率较低。

    老年代GC (Major GC /  Full GC) 频率低,速度比 Minor GC慢十倍以上

 

 

  java的四种引用类型:

  • 强引用(StrongReference)
    • 具有强引用的对象不会被GC;
    • 即便内存空间不足,JVM宁愿抛出OutOfMemoryError使程序异常终止,也不会随意回收具有强引用的对象。
    • Object obj = new Object();    //  只有当obj 这个引用释放后,才会回收该对象
  • 软引用(SoftReference)
    • 只具有软引用的对象,会在内存空间不足的时候被GC,如果回收之后内存仍不足,才会抛出OOM异常;
    • Object obj = new Object();  
    • SoftReference<Object> sf = new SoftReference<Object>(obj);
    •  可以用 sf.get() 获取对象,当对象被标记为需要回收的对象时,返回null
    • 软引用主要实现类似缓存功能,当内存足够时通过软引用取值,不从繁忙的真实来源查询数据,提升速度。
    •   当内存不足时,自动删除这部分缓存数据,从真实来源查询数据。
  • 弱引用(WeakReference)
    • 只被弱引用关联的对象,无论当前内存是否足够都会被GC;
    • 强度比软引用更弱,常用于描述非必需对象。
    • Object obj = new Object();
      WeakReference<Object> wf = new WeakReference<Object>(obj);
      短时间内通过 wf.get()能获得对象,当执行过第二次垃圾回收后,将返回null
    • 用 wf.isEnQueued() 确认是否被垃圾回收器标记为即将回收
  • 虚引用(PhantomReference)
    • 仅持有虚引用的对象,在任何时候都可能被GC;
    • 常用于跟踪对象被GC回收的活动;
    • 必须和引用队列 (ReferenceQueue)联合使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。
    • Object obj = new Object();
      PhantomReference<Object> pf = new PhantomReference<Object>(obj);
      pf.get();//永远返回null
      pf.isEnQueued();//返回是否从内存中已经删除



 

posted @ 2019-04-25 13:43  Joooseph  阅读(174)  评论(0编辑  收藏  举报