JVM中的垃圾回收机制

这篇具有很好参考价值的文章主要介绍了JVM中的垃圾回收机制。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、什么是垃圾回收

java相较于c、c++语言的优势之一是自带垃圾回收器,垃圾回收是指不定时去堆内存中清理不可达对象。不可达的对象并不会马上就会直接回收, 垃圾收集器在一个Java程序中的执行是自动的,不能强制执行,程序员唯一能做的就是通过调用System.gc 方法来建议执行垃圾收集器,但其是否可以执行,什么时候执行却都是不可知的。这也是垃圾收集器的最主要的缺点。当然相对于它给程序员带来的巨大方便性而言,这个缺点是瑕不掩瑜的。

二、为什么需要垃圾回收

如果不进行垃圾回收,内存迟早都会被消耗空,因为我们在不断的分配内存空间而不进行回收。除非内存无限大,我们可以任性的分配而不回收,但是事实并非如此。所以,垃圾回收是必须的。

三、java中的四种引用类型

强引用

Object obj = new Object(); //只要obj还指向Object对象,Object对象就不会被回收
obj = null;  //手动置null,可以通过System.gc方法进行回收处理

我们一般声明对象时虚拟机生成的引用,强引用环境下,垃圾回收时需要严格判断当前对象是否被强引用,如果被强引用,就说明他不是垃圾,则不会被垃圾回收。

软引用
软引用一般被做为缓存来使用。与强引用的区别是,软引用在垃圾回收时,虚拟机会根据当前系统的剩余内存来决定是否对软引用进行回收。如果剩余内存比较紧张,则虚拟机会回收软引用所引用的空间;如果剩余内存相对富裕,则不会进行回收。换句话说,虚拟机在发生OutOfMemory时,肯定是没有软引用存在的。

弱引用
弱引用也是用来描述非必需对象的,但是它的强度比软引用更弱一些,**被弱引用关联的对象只能生存到下一次GC发生之前,当垃圾收集器工作时,无论当前内存是否足够,都会回收掉该类对象。**弱引用对象在回收时会被放入引用队列(ReferenceQueue)。

虚引用
虚引用被称为幽灵引用或幻象引用,它是最弱的一种引用关系。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得对象实例。任何时候都可能被回收,一般用来跟踪对象被垃圾收集器回收的活动,起哨兵作用。必须和引用队列(ReferenceQueue)联合使用。

这些概念可能有点抽象,不过这四种引用具有不同的垃圾回收时机应该是很清楚的。我们会发现,引用的强度从强、软、弱、虚依次递减,越往后的引用所引用的对象越容易被垃圾回收。

四、垃圾识别机制

1.引用计数算法

引用计数算法是判断对象是否存活的算法之一:它给每一个对象加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能被使用的,即将被垃圾回收器回收。

缺点:
1.他需要单独的字段存储计数器,这样的做法增加了存储空间的开销。
2.无法解决对象减互相循环引用的问题。即当两个对象循环引用时,引用计数器都为1,当对象周期结束后应该被回收却无法回收,造成内存泄漏。

public class GcTest {
    public static void main(String[] args) {       
      MyObject myObject_1 = new MyObject();       
      MyObject myObject_2 = new MyObject();                
      myObject_1.instance = myObject_2;        
      myObject_2.instance = myObject_1;
      myObject_1 = null;        
      myObject_2 = null;  
      System.gc();    
      }  
      // 对象循环引用,用引用计数算法时,无法回收这两个对象            

2.可达性分析算法

目前主流使用的都是可达性分析算法来判断对象是否存活。算法基本思路:以“GC Roots”作为对象的起点,从此节点开始向下搜索,搜索所走过的路径成为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。
jvm垃圾回收机制,java,jvm,java,算法
哪些对象可作为GC Roots?
虚拟机栈(栈帧中的本地变量表)中引用的对象;
方法区中类静态属性引用的对象;
方法区中常量引用的对象;
本地方法栈中JNI(Native方法)引用的对象;
活跃线程的引用对象。

五、finalize()赋予对象重生

finalize()是Object的protected方法,子类可以覆盖该方法以实现资源清理工作,GC在回收对象之前调用该方法。

在可达性分析算法中被标记为不可达的对象,也不一定是一定会被回收,它还有第二次重生的机会。每一个对象在被回收之前要进行两次标记,一次是没有关联引用链会被标记一次,第二次是判断该对象是否覆盖finalize()方法,如果没有覆盖则真正的被定了“死刑”。

代码实现

public class FinalizeTest {
    public static FinalizeTest ft;
    /**
     * 用于判断对象是死亡还是存活
     */
    public static void judge(){
        if(ft == null){
            System.out.println("i am dead");
        }else{
            System.out.println("i am alive");
        }
    }
    public static void main(String[] args) throws InterruptedException {
        ft = new FinalizeTest();
 
        // 将引用指向null,那么对象就没有任何关联了
        ft = null;
        // 触发一次gc
        System.gc();
        // 因为Finalizer线程的优先级低,因此sleep 1秒后再看结果
        Thread.sleep(1000);
        //因为FinalizeTest对象覆盖了finalize方法,并在该方法中重新建立与引用的关联,所以对象会复活
        judge();
        //下面的代码和上面的一模一样,但是对象不会再复活了,因为finalize方法最多执行一次
        ft = null;
        System.gc();
        Thread.sleep(1000);
        judge();
    }
 
    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("执行finalize方法");
        // 对象复活的关键:重新建立与引用的关联
        ft = this;
    }
}

流程图(finalize()存在时)

jvm垃圾回收机制,java,jvm,java,算法

六、四种垃圾回收算法

确认完垃圾之后肯定要想办法回收垃圾。回收垃圾主要有下面四种方法:标记清除算法、标记整理算法、复制算法、分代收集算法。

标记清除算法

算法思路:算法分为“标记”和“清理”两个步骤,首先标记处所有需要回收的对象,在标记完成后再统一回收所有被标记的对象。

缺陷:
1.标记和清理的两个过程效率都不高;
2.容易产生内存碎片,碎片空间太多可能导致无法存放大对象。

适用于存活对象占多数的情况。
jvm垃圾回收机制,java,jvm,java,算法

标记整理算法

算法思路:标记过程和标记-清理算法一样,而后面的不一样,它是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存
jvm垃圾回收机制,java,jvm,java,算法

复制算法

算法思路:将可用内存划分为大小相等的两块,每次只使用其中的一块。当这一块内存用完后,就将还存活的对象复制到另一块去,然后再把已使用过的内存空间一次清理掉。

缺陷:
可用内存缩小为了原来的一半
算法执行效率高,适用于存活对象占少数的情况。
jvm垃圾回收机制,java,jvm,java,算法

分代收集算法

当前大多数垃圾收集都采用的分代收集算法,这种算法并没有什么新的思路,只是根据对象存活周期的不同将内存划分为几块,每一块使用不同的上述算法去收集。在jdk8以前分为三代:年轻代、老年代、永久代。在jdk8以后取消了永久代的说法,而是元空间取而代之。

在新生代,每次垃圾收集器都发现有大批对象死去,只有少量存活,采用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。
老年代
而老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须“标记-清除-压缩”算法进行回收。

Minor GC和Full GC区别

新生代 GC(Minor GC):指发生在新生代的垃圾收集动作,因为 Java 对象大多都具备朝生夕灭的特性,所以 Minor GC 非常频繁,一般回收速度也比较快。
老年代 GC(Major GC / Full GC):指发生在老年代的 GC,出现了 Major GC,经常会伴随至少一次的 Minor GC(但非绝对的,在 ParallelScavenge 收集器的收集策略里就有直接进行 Major GC 的策略选择过程) 。MajorGC 的速度一般会比 Minor GC 慢 10倍以上。

jvm垃圾回收机制,java,jvm,java,算法
年轻代分为伊甸园区和幸存区,幸存区分为from和to区。每次执行GC操作,会将伊甸园区和from区存活的对象放到to区(如果to区不够,则直接进入老年代),然后将from区和to区的职责交换(from区变为to区,to区变为from区,谁空谁是to区)。
jvm垃圾回收机制,java,jvm,java,算法

新生代中的对象98%都是朝生夕死的,因此把新生代分为较大的一块Eden空间和两块较小的Survivor空间,每次使用Eden和其中的一块Survivor(此处Survivor区也叫From区,另一块空的未使用的空间叫To区,From和To区是会交换的,保证空的总是To区)。

当Eden区没有足够的空间分配时,会进行一次Minor GC,Eden区大部分对象都被回收,而Eden区和From区存活的对象会放入到To区,然后From和To区进行交换。(如果To区空间不够,直接进入老年代)

以下几种情况会进入老年代。

1、 大对象
大对象就是指需要大量连续内存空间的对象,最典型的就是那种很长的字符串和数组。大对象会直接进入到老年代,这样做的目的主要是为了避免新生代发生大量的内存复制(大对象的复制成本较高)。

2、长期存活的对象
虚拟机给每个对象都定义了一个对象年龄计数器。每当进行一次Minor GC,年龄就增加1岁,当年龄超过一定值时(默认是15,可以通过参数配置),就进入到老年代。

动态对象年龄判断
虚拟机并不要求对象年龄一定要到达15岁才进入到老年代。如果Survivor空间中有某年龄相同的所有对象大小总和大于Survivor空间的一半,则年龄大于等于该年龄的对象就会直接进入老年代。文章来源地址https://www.toymoban.com/news/detail-575091.html

到了这里,关于JVM中的垃圾回收机制的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 深入探讨Java虚拟机(JVM):执行流程、内存管理和垃圾回收机制

    深入探讨Java虚拟机(JVM):执行流程、内存管理和垃圾回收机制

    目录 什么是JVM? JVM 执行流程 JVM 运行时数据区 堆(线程共享) Java虚拟机栈(线程私有) 什么是线程私有? 程序计数器(线程私有) 方法区(线程共享) JDK 1.8 元空间的变化 运行时常量池 内存布局中的异常问题 1.  Java堆溢出 2.  虚拟机栈和本地方法栈溢出 JVM 类加载 1.

    2024年02月09日
    浏览(13)
  • 【Java】图解 JVM 垃圾回收(一):GC 判断策略、引用类型、垃圾回收算法

    【Java】图解 JVM 垃圾回收(一):GC 判断策略、引用类型、垃圾回收算法

    垃圾 是指运行程序中 没有任何引用指向的对象 ,需要被回收。 内存溢出 :经过垃圾回收之后,内存仍旧无法存储新创建的对象,内存不够溢出。 内存泄漏 :又叫 “ 存储泄漏 ”,对象不会再被程序使用了,但是 GC 又不能回收它们。例如:IO 流不适用了但是没有被 Close、

    2024年02月19日
    浏览(11)
  • JVM基础(3)——JVM垃圾回收机制

    JVM基础(3)——JVM垃圾回收机制

    作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO 联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬 学习必须往深处挖,挖的越深,基础越扎实! 阶段1、深入多线程 阶段2、深入多线程设计模式 阶段3、深入juc源码解析

    2024年01月25日
    浏览(7)
  • 【JVM】垃圾回收机制

    【JVM】垃圾回收机制

     哈喽,哈喽,大家好~ 我是你们的老朋友: 保护小周ღ    今天给大家带来的是  JVM (Java 虚拟机) 的垃圾回收机制,回收是指回收什么?  如何确定要回收的内存: 引用计数,可达性分析,如何释放空间 : 标记清除,复制算法,标记整理,分代回收 ,一起来看看叭~ 本期

    2024年02月09日
    浏览(7)
  • 浅谈JVM垃圾回收机制

    新生代收集(Minor GC/Young GC):只对新生代进行垃圾收集 老年代收集(Major GC/Old GC):只队老年代进行垃圾收集 混合收集(Mixed GC):对整个新生代和老年代进行垃圾收集 收集整个Java堆和方法区 空间分配担保是为了确保在Minor GC之前老年代还有容纳新生代所有对象的剩余空间 垃圾回收算

    2024年02月10日
    浏览(9)
  • JVM及垃圾回收机制

    JVM及垃圾回收机制

    类加载器负责将.class文件加载到JVM中。主要分为三种层次:Bootstrap ClassLoader、Extension ClassLoader和Application ClassLoader。它们按层次关系加载类,保证类的隔离性和重用性。 运行时数据区包括方法区、堆、栈、本地方法栈和程序计数器。堆用于存放对象实例,方法区保存类信息和

    2024年02月12日
    浏览(6)
  • 【JVM】JVM执行流程 && JVM类加载 && 垃圾回收机制等

    【JVM】JVM执行流程 && JVM类加载 && 垃圾回收机制等

    目录 🌷1、JVM是什么? 🌷2、JVM的执行流程(能够描述数据区5部分) 🌷3、JVM类加载过程 🌷4、双亲委派机制:描述类加载的过程 问题1:类加载器 问题2:什么是双亲委派模型?  问题3:双亲委派模型的优点 🌷5、垃圾回收机制(重要,针对的是堆)    问题1:判定对象

    2024年02月15日
    浏览(9)
  • JVM:垃圾回收机制(GC)

    JVM:垃圾回收机制(GC)

    引用计数算法:         在对象中添加一个引用计数器,当每有一个地方引用它时,计数器值加一。当引用失效时,计数器值就减一。当一个对象的计数器为零时,表示该对象没有被任何其他对象引用,因此可以被释放。 优点 :是可以及时回收垃圾对象,避免内存泄漏,且

    2024年01月19日
    浏览(9)
  • 【JVM】垃圾回收机制详解(GC)

    【JVM】垃圾回收机制详解(GC)

    可以看jvm详解之后,再来理解这篇文章更好 堆和方法区,主要发生在堆中,然后主要发生在堆的伊甸园区(Eden)。 Java中的垃圾回收是根据 可达性分析算法(Reachability Analysis) 和 引用计数算法 来判断对象是否存活的。 JDK.1.2 之后,Java 对引用的概念进行了扩充,将引用分为了:

    2024年02月13日
    浏览(7)
  • 【JVM】| 垃圾回收机制 | 文末送书

    【JVM】| 垃圾回收机制 | 文末送书

    Java的垃圾回收机制是自动的,不需要程序员手动进行内存管理。当Java应用程序创建对象时,它们存储在堆内存中。当对象不再被引用时,垃圾回收器会自动标记这些对象为垃圾,并将它们从堆内存中清除,释放空间。 如果要操作对象,必须通过引用来进行。如果一个对象没

    2024年02月13日
    浏览(6)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包