文章目录

  • JVM垃圾回收机制
    • 1 判断对象是否存活的算法
      • 1.1 引用计数器算法
      • 1.2 可达性分析算法
    • 2 对象的四种引用方式
      • 2.1 强引用
      • 2.2 软引用
      • 2.3 弱引用
      • 2.4 虚引用
    • 3 垃圾回收算法
      • 3.1 标记-清除算法
      • 3.2 复制算法
      • 3.3 标记-整理算法
    • 4 JVM 分代垃圾回收机制

JVM垃圾回收机制

1 判断对象是否存活的算法

堆内存进行垃圾回收,需要判断哪些对象已死

1.1 引用计数器算法

  • 为对象添加一个引用计数器,当有一个地方引用该对象时,计数器+1,当引用失效时,计数器-1,当计数器为0,说明该对象已死;

  • 引用计数器算法实现简单、效率高,适用于大多数适用场景,但是主流的JVM均没有采用了这种算法,原因在于它很难解决对象之间的相互循环引用情况,容易形成僵尸对象,发生内存泄漏;

1.2 可达性分析算法

在主流的商用虚拟机中都是通过可达性分析算法来判断对象是否存活,这个算法核 心思想就是通过一个“GCRoots”的对象做为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到“GC Roots”没有任何引用链相连,则证明该对象不再被引用。

GCRoots:外部变量,他可以是(本地方法栈,虚拟机栈,方法区)任意变量;

  • 虚拟机栈(栈帧中的局部变量表)中引用的对象。(可以理解为:引用栈帧中的局部变量表的所有对象)
  • 方法区中静态属性引用的对象(可以理解为:引用方法区该静态属性的所有对象)
  • 方法区中常量引用的对象(可以理解为:引用方法区中常量的所有对象)
  • ​ 本地方法栈中(Native 方法)引用的对象(可以理解为:引用 Native 方法的所有对象)

2 对象的四种引用方式

无论是通过引用计数器还是通过可达性分析判断对象是否存活都跟引用有关;

在 JDK1.2 以前,Java 中引用的定义很传统: 如果引用类型的数据中存储的数值代表的是另一块内存的起始地址,就称这块内存代表着一个引用。这种定义有些狭隘,一个对象在这种定义下只有被引用或者没有被引用两种状态。

public class A(){b.say();b=null;//当我们想再次使用该对象需要重新引用,JDK1.2之前只有该引用方法,但是该引用方式不能满足我们实际需求B b1 =new B();
}
class B(){}

我们希望能描述这一类对象: 当内存空间还足够时,则能保存在内存中;如果内存空间 在进行垃圾回收后还是非常紧张,则可以回收这些对象。很多系统中的缓存对象都符合这样的场景。

在 JDK1.2 之后,Java 对引用的概念做了扩充,将引用分为强引用软引用弱引用虚引用四种,这四种引用的强度依次递减。

2.1 强引用

B b =new B();

  • 强引用只有两种状态,正在被引用和未被引用;

    如果一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java 虚拟机宁愿抛出 OutOfMemoryError 错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。

2.2 软引用

  • 软引用描述一些,还有用,但非必要的对象,如果内存空间充足,垃圾回收器不会回收,如果空间不充足,就会回收这些对象的内存。

  • 软引用可以实现一些内存高度敏感的内存

    JDK1.2使用java.lang.ref.SoftReference来实现软引用

    class A{public void say(){System.out.println("im a say()");}@Overrideprotected void finalize() throws Throwable {System.out.println("A类的对象被垃圾回收器清理");}
    }
    
    public class SoftReferenceDemo {public static void main(String[] args) {A a =new A();//强引用System.out.println(a);//查看强引用地址a.say();//强引用调用//将a对象设置为软引用SoftReference<A> softReference =new SoftReference<A>(a);System.out.println(a);//查看软引用地址a=null;System.gc();softReference.get().say();//软引用未被回收//从软引用中获取a对象,赋值给a,对象由回到强引用状态a = softReference.get();a =null;System.gc();System.out.println(a);}
    }
    

    运行控制台输出

    com.jiazhong.jvm.引用.A@4554617c   //查看强引用地址
    im a say()                        //强引用调用
    com.jiazhong.jvm.引用.A@4554617c //查看软引用地址
    im a say()                       //软引用未被回收
    null
    

    软引用为空后,内存不会回收,直至内存不足

2.3 弱引用

  • 弱引用与软引用的区别在于:具有弱引用的对象拥有更短暂的生命周期,它仅仅能够生存到垃圾回收之前,当垃圾收集时,无论内存是否足够,弱引用的对象都要被回收

    JDK1.2 以后使用 java.lang.ref.WeakReference类来实现弱引用

    public class WeakReferenceDemo {public static void main(String[] args) {A a =new A();System.out.println(a);  //强引用地址a.say();                //强引用调用say()WeakReference<A> weakReference =new WeakReference<A>(a);System.out.println(a);  //弱引用地址a = null;weakReference.get().say();//弱引用调用say()System.gc();weakReference.get().say();//弱引用被回收了}
    }
    
    com.jiazhong.jvm.引用.A@4554617c    //强引用地址
    im a say()                       //强引用调用say()
    com.jiazhong.jvm.引用.A@4554617c //弱引用地址
    im a say()                       //弱引用调用say()
    A类的对象被垃圾回收器清理            //弱引用被回收了,调用say()空指针异常
    Exception in thread "main" java.lang.NullPointerExceptionat com.jiazhong.jvm.引用.WeakReferenceDemo.main(WeakReferenceDemo.java:15)
    

    弱引用,在内存回收后,就会被回收了

2.4 虚引用

  • “虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。

    如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。

    也无法通过虚引用获得一个实例对象;

    作用:

    • 使用虚引用的目的就是可以作为对象清理的通知来使用,当该对象被清理后,会将该对象放入其第二个参数的引用队列中,如果队列有改对象,表名对象被清理。

    • 虚引用是一个对象被清理的通知机制,他是对象被清理后的一种通知,接到该通知后,对象清理后可以做一下其他清理工作。

    • 虚引用无法同finalize()方法一起使用,如果使用finalize()清理则不能使用虚引用的通知机制,如果使用虚引用的通知则不能使用finalize()清理

    如果持有虚引用的对象重写了 finalize()方法则表示在对象被垃圾回收器清理前要做清理工作,此时虚引用的对象直接被清理不进入引用队列

    JDK1.2 以后使用 java.lang.ref.ReferenceQueue 类来实现引用队列

    public class PhantomReferenceDemo {public static void main(String[] args) {A a =new A();a.say();/*** 设置虚引用* 参数1:虚引用的对象* 参数2:引用队列*/ReferenceQueue<? super A> referenceQueue =new ReferenceQueue<>();PhantomReference<A>  phantomReference =new PhantomReference<A>(a,referenceQueue);a = null;
    //        System.out.println(phantomReference.get());//无法获取System.gc();System.out.println("sssssssss");System.out.println(referenceQueue.poll());}
    }
    
    im a say()
    A类的对象被垃圾回收器清理
    

    虚引用在任何时候,都会被垃圾回收

    启用System.gc()开启了一个子线程进行垃圾回收;加入System.out.println("sssssssss");等同于有了一个时间差,给System.gc()有了清理对象的时间,清理后就会将该对象放入引用队列中去;

    因为在使用PhantomReference重写了get()方法,让其返回为null,所以phantomReference.get()也找不回来被虚引用引用的对象


引用队列,指的是对象被清理之后放入的地方,不仅可以和虚引用同时使用,也可以和其他引用同时使用。


3 垃圾回收算法

3.1 标记-清除算法

“标记-清除”算法是最基础的收集算法。

算法分为标记和清除两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象(标记过程通过可达性分析实现)。后续的收集算法都是基于这种思路并对其不足加以改进而已。

“标记-清除”算法的不足主要有两个:

效率问题:标记和清除这两个过程的效率都不高

空间问题:标记清除后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在 程序运行中需要分配较大对象时,无法找到足够连续内存而不得不提前触发另一次垃圾收集。

3.2 复制算法

“复制”算法是为了解决“标记-清除”的内存碎片问题。它将可用内存按容量划分为 大小相等的两块,每次只使用其中一块。当这块内存需要进行垃圾回收时,会将此区域还存活着的对象复制到另一块上面,然后再把已经使用过的内存区域一次清理掉。

优点:整个半区进行内存回收,内存分配时也就不需要考虑内存碎片等的复杂情况,只需要移动堆顶指针,按顺序分配即可。此算法实现简单,运行高效。

缺点:由于每次都要预留出 50%的空间不能存放对象,内存利用率低,内存空间严重浪费。

3.3 标记-整理算法

标记过程仍与“标记-清除”过程一致,但后续步骤不是直接对可回收对象进行清理,而是让所有存活对象向一端移动,然后直接清理掉端边界以外的内存。

整理过程依然麻烦,效率不高

4 JVM 分代垃圾回收机制

  1. 新生代垃圾回收

新生代使用用复制算法来进行垃圾回收,由于新生代中 98%的对象都是"朝生夕死"的, 所以并不需要按照 1 : 1 的比例来划分内存空间,而是将内存(新生代内存)分为一块较大的 Eden(生成区)空间和两块较小的 Survivor(幸存者)空间

当 Survivor 空间不够用时,JVM 使用内存担保的机制将 Survivor 空间存活的对象转移到老年代。

HotSport 默认 Eden 与 Survivor 的大小比例是 8 : 1,也就是说 Eden:Survivor From : Survivor To = 8:1:1。所以每次新生代可用内存空间为整个新生代容量的 90%, 而剩下的 10%用来存放回收后存活的对象。

流程详见:JVM(超级无敌认真好用,万字收藏篇!!!)第五章-堆

  1. 老年代垃圾回收

老年代中对象存活率高、没有额外空间对它进行分配担保,就必须采用"标记-整理"算法


  • 学习来自于西安加中实训

JVM垃圾回收机制(超级无敌认真好用,万字收藏篇!!!!)相关推荐

  1. 4、JVM垃圾回收机制、新生代的GC、GC(Minor GC、FullGC)、GC日志、JVM参数选项、元空间(笔记)

    4.JVM垃圾回收机制 4.1.新生代的GC 4.1.1.串行GC(SerialGC) 4.1.2.并行回收GC(Parallel Scavenge) 4.1.3.并行GC(ParNew) 4.2.G ...

  2. jvm垃圾回收机制_JVM 垃圾回收机制之堆的分代回收

    JVM垃圾回收机制之堆的分代回收 前言 前文我们了解了Java的GC机制,对于堆中的对象,JVM采用引用计数和可达性分析两种算法来标记对象是否可以清除,本文中我们还会了解到JVM将对分成了不同的区域, ...

  3. jvm对象从新生代到老年代_JVM内存管理、JVM垃圾回收机制、新生代、老年代以及永久代...

    内存模型 JVM运行时数据区由程序计数器.堆.虚拟机栈.本地方法栈.方法区部分组成,结构图如下所示. JVM内存结构由程序计数器.堆.栈.本地方法栈.方法区等部分组成,结构图如下所示: 1)程序计数器 ...

  4. JVM内存区域(Java内存区域)、JVM垃圾回收机制(GC)初探

    一.JVM内存区域(Java内存区域) 首先区分一下JVM内存区域(Java内存区域)和Java内存模型(JMM)的概念.Java线程之间的通信采用的是共享内存模型,这里提到的共享内存模型指的就是Ja ...

  5. JVM架构、JVM垃圾回收机制、垃圾回收算法、垃圾回收器、JMM(内存模型)

    0 JVM和Java的关系 JDK = JRE + Java开发工具(java,javac,javadoc,javap-) JRE = JVM + Java核心类库 即: JDK = JVM + Ja ...

  6. 2.JVM垃圾回收机制-什么时候回收内存

    在前面的文章中,我们介绍过JVM垃圾回收机制负责的是堆和方法区的内存. 参考:http://blog.csdn.net/u011983531/article/details/49227013 在本篇中 ...

  7. JVM垃圾回收机制及算法

    JVM垃圾回收机制 在Java中,程序员是不需要像C++那样显示的去释放一个对象的内存的,而是由虚拟机自行执行.在JVM中,有一个垃圾回收线程,它是低优先级的,在正常情况下是不会执行的,只有在虚拟机空 ...

  8. 【JVM】JVM垃圾回收机制GC

    文章目录 JVM垃圾回收机制 一.堆内存区域划分 1.1内存分配策略 1.2永久代(Permanent Generation) 1.3元空间(MetaSpace) 二.标记算法 2.1引用计数算法 2 ...

  9. Java小记-Vue/ElementUI/Axios(超级无敌认真好用,万字收藏篇!!!!)

    文章目录 Vue/ElementUI/Axios 前言 1 Vue简介 2 Vue的安装 3 Vue的简单使用 4 Vue的指令 4.1 什么是Vue的指令 4.2 Vue常用指令 5 Element ...

最新文章

  1. 华为面试题之大整数相加
  2. node JS獲取GPS_Node.js 14 正式发布:V8 引擎升级,新增异步本地存储 API
  3. UI5 libraries determined in Backend
  4. HTML的基本知识(六)——表格的基本属性之实现个人简历
  5. iOS关键代码遭泄露;Google正式抛弃HTTP;微博网页版出故障 | 一周业界事
  6. Java日期与时间的处理/Date,String,Calendar转换
  7. elasticsearch 分组求和
  8. matlab神经网络预测数据,Matlab神经网络预测复数
  9. 浙江大学公开课《王阳明心学》
  10. python识别文字坐标_python识别图片上的文字并返回文字在图片中的坐标
  11. 超级大富翁主题团建活动
  12. 网站单页面优化的6个技巧
  13. 微生物组-扩增子16S分析和可视化(线上/线下同时开课,2022.4)
  14. HTTPS数字证书原理
  15. 读 PHP - Pimple 源码笔记(下)
  16. 精卫填海——大数据安全与隐私保护
  17. mybatis的原理详解
  18. 北大计算机在本部吗,北大本部和北大医学部都属于北京大学,那么两者有什么区别?...
  19. 细聊 正则表达式 (附demo)
  20. java计算机毕业设计绿色生活基于PS、DW的绿色环保宣传网站源码+数据库+系统+lw文档+mybatis+运行部署

热门文章

  1. 第三章:从此你就叫张三了!-变量,痴月熊学python
  2. vue3玩转i18n
  3. csgo躲猫猫显示服务器已满,csgo躲猫猫模式在哪里可以玩?
  4. 首届“互联网+交通出行服务”论坛在北京召开
  5. C# 获取List集合中指定几行的数据
  6. task07 类与对象、魔方方法
  7. 51单片机中 bit和sbit区别
  8. HashMap遍历以及遍历顺序
  9. python笔记72 - 使用pathlib替代os.path
  10. 如何在List中放部分实体_适用大部分实体店的引流设计案例:如何用买客户思维设计鱼饵!...