代码编织梦想

👨‍💻个人主页: 才疏学浅的木子
🙇‍♂️ 本人也在学习阶段如若发现问题,请告知非常感谢 🙇‍♂️
📒 本文来自专栏: JVM
❤️ 支持我:👍点赞 🌹收藏 🤟关注

概述

垃圾收集器需要完成的三件事

那些内存需要回收?
什么时候回收?
如何回收?

那些需要进行GC

程序计数器、虚拟机栈、本地方法栈3个区域随线程而生,随线程灭而灭,栈中的栈帧随着方法的进入和退出有条不紊的进行出栈和入栈操作。每一个栈帧中分配多少内存基本上是在类结构确定下来时就已知(尽管在运行期间会由即时编译器进行一些优化,但在基于概念模型的讨论里,大体上可以认为是已知的),因此这几个区域内存的分配和回收都具备确定性,在这几个区域内就不需要过多考虑回收的问题,当方法结束或者线程结束时,内存自然就随着回收了
Java堆和方法区这两个区域则有着很显著的不确定性:一个接口的多个实现类需要的内存可能会不一样,一个方法所执行的不同条件分支所需要的内存也可能不一样,只有处于运行期间,我们才能知道这个程序究竟会创建那些对象。

如何判断对象是否该被回收?

引用计数法

在对象里面添加一个引用计数器,每当有一个对象引用它时,计数器值就加一;每当引用失效,计数器的值就减一;任何时刻计数器为零的对象就是不可能再被使用的

/**
 * @className: JVM_1
 * @description: 测试JVM是否使用引用计数法
 * @author: 热爱生活の李
 * @since: 2022/5/20 14:52
 */
public class JVM_1 {
    public Object instance = null;
    private static final int _1MB = 1024 * 1024;

    public static void main(String[] args) {
        JVM_1 objectA = new JVM_1();
        JVM_1 onjectB = new JVM_1();
        objectA.instance = onjectB;
        onjectB.instance = objectA;

        objectA = null;
        onjectB = null;
        System.gc();
    }
}

在这里插入图片描述

添加GC日志打印
运行配置里加VM option
参数为 -XX:+PrintGCDetails

缺点
可能会造成循环引用,导致无法回收,例如:上面对象objectA和objectB都有字段instance,objectA.instance = objectB,objectB.instance = objectA,除此之外,这两个对象再无其他任何引用,实际上这两个对象不可能被访问,但是他们互相引用对方,导致引用计数器不为0,就无法回收它们。

可达性分析算法

通过一系列称为“ GC Roots ” 的根对象作为起始节点集,从这些节点开始,根据引用关系向下搜索,搜索过程所走过的路径称为“ 引用链 ” ,如果某个对象到GC Roots 间没有任何链相连,或者用图论的话来说就是从GC Roots到这个对象不可达时,则证明对象不可能再被使用

在这里插入图片描述

那些可以作为GC Roots对象

固定作为GC Roots
1、在虚拟机栈中引用的对象(各个线程被调用的方法栈中的参数、局部变量、临时变量)
2、在方法区中类静态属性引用的对象(Java类的引用类型静态变量)
3、在方法区常量引用的对象(字符串常量池String Table的引用)
4、在本地方法栈中引用的对象(Native方法)
5、Java虚拟机内部的引用(基本数据类型对应的Class对象,一些常驻的异常对象比如NullPointException,还有系统类加载器)
6、所有被同步锁(synchronized关键字)持有的对象
7、反映Java虚拟机内部情况的JMXBean、JVMTL注册的回调、本地代码缓存等

根据用户所选择的垃圾收集器以及当前回收的内存区域不同,还可以用其他对象"临时性"地加入

引用

Java对引用的概念进行了扩充,将引用分为强引用(Strongly Reference)、软引用(Soft Reference)、弱引用(Weak Reference)和虚引用(Phantom Reference)

强引用: 指在程序代码之间存在的引用赋值,即类型Object obj = new Object() 这种引用关系。无论任何关系下,只要强引用关系还存在,垃圾收集器就不会回收掉被引用的对象
软引用: 用来描述一些还有用,但非必须的对象。只被软引用关联着的对象,在系统将要发生内存溢出异常前,会把这些对象列进回收范围之中进行第二次回收,如过这次回收还是没有足够的内存,才会抛出内存溢出异常。
弱引用: 用来描述那些非必要对象,但是它的强度比软引用更弱一些,关联的对象只能生存到下一次垃圾收集为止。当垃圾收集器开始工作,无论当前内存是否足够,都会回收掉只被弱引用关联的对象
虚引用: 最弱的一种引用关系。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实列。为一个对象设置虚引用关联的唯一目的只是为了能在这个对象被收集器回收的时候收到一个系统通知。

生存还是死亡

即使是在可达性分析算法中判断为不可达的对象也不是非死不可,要真正宣告一个对象死亡,至少要经历两次标记过程。

在这里插入图片描述

package JVM;
/**
 * @className: JVM_2
 * @description: 测试finalize()方法
 * @author: 热爱生活の李
 * @since: 2022/5/20 15:08
 */
public class JVM_2 {
    public static JVM_2 instance = null;
    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("finalize 方法执行了 !!!");
        JVM_2.instance = this;
    }

    public static void main(String[] args) throws InterruptedException {
        instance = new JVM_2();
        instance = null;
        System.gc();
        // finalizer方法优先级很低
        Thread.sleep(5000);
        if(instance != null){
            System.out.println("我还活着 !!!");
        }else {
            System.out.println("我死了 !!!");
        }
        instance = null;
        System.gc();
        Thread.sleep(5000);
        if(instance != null){
            System.out.println("我还活着 !!!");
        }else {
            System.out.println("我死了 !!!");
        }
    }
}

在这里插入图片描述

finalize()方法只会被调用一次

回收方法区

方法区的垃圾收集主要回收两部分内容:废弃的常量和不再使用的类型

回收废弃的常量
假如一个字符串“Java” 曾经进入常量池,但是当前系统又没有任何一个字符串对象的值是“Java”,换句话说已经没有任何字符串对象引用常量池中的”Java“常量,且虚拟机中也没有其他地方引用这个字面量。如果这时发生内存回收,而且垃圾收集器判断有必要的话,这个”Java“常量就会被清理出常量池。常量池中其他类(接口)、方法、字段的符号引用也与此类似

回收类型的判断条件
1、该类的所有实例化都已经被回收,也就是Java堆中不存在该类及其任何派生子类的实例
2、加载该类的类加载器已经被回收
3、该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法

Java虚拟机被允许对满足上述三个条件的无用类进行回收,这里说的仅仅是被允许,而并不是和对象一样,没有引用就被必然被回收。
关于是否要对类型进行回收,HotSpot虚拟机提供了 -Xnoclassgc 参数进行控制,还可以使用 -verbose:class 以及 -XX:+TraceClassLoading、-XX:TraceClassUnLoading 查看类加载和卸载信息

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/m0_74787523/article/details/128018778

jvm——引用计数算法和可达性分析算法——判断对象是否需要被回收_信恒涛的博客-爱代码爱编程

Java程序运行时,所有的实例对象都保存在Java堆里,而大量的实例对象会占用大量的内存空间,保证内存的可用性,需要对不用的对象进行垃圾回收,而进行垃圾回收之前最重要的就是判断某一个对象是否可以被回收,当一个对象不能再被任何途径访问,说明该对象已经没有用了。         下面介绍两种判断对象是否还会被引用的算法——引用计数算法和可达性分析法      

java jvm 4-gc对象判断算法:引用计数法,可达性分析算法_xucc_的博客-爱代码爱编程

 因为JVM的GC(垃圾回收)机制,所以使java程序员不用再受内存分配及内存回收的烦恼(其实还是会有这些烦恼,我们以后再进行探讨),而可以将注意力集中在程序的设计上,虽然我们不用再关心这些过程,但是GC的垃圾回收我们还是要

jvm----判断对象是否存活 : 引用计数算法or可达性分析算法?_no0b的博客-爱代码爱编程

本篇来自周志明的<<深入理解java虚拟机>> 在堆里面存放着Java世界中几乎所有的对象实例,垃圾收集器在对堆进行回收前,第一件事情就是要确定这些对象之中哪些还“存活”着 ,哪些已经“死去”(即不可能再被任何途径使用的对象)。 引用计数算法 很多教科书判断对象是否存活的算法是这样的:给对象中添加一个引用计数器,每当有—个地方

jvm——引用计数算法与可达性分析算法-爱代码爱编程

前几篇博客我们一起认识了JVM的内存模型(程序计数器、虚拟机栈、本地方法栈、方法区与堆),了解了它们的内存结构与分配,同时也略带提到关于内存的回收。 JVM——内存模型(一):程序计数器 JVM——内存模型(二):虚拟机栈与本地方法栈 JVM——内存模型(三):堆与方法区 有内存分配就肯定有内存回收,这个大家都知道,可哪些东西需要回收?什么时候进行

Java中的两种垃圾分析算法详解-爱代码爱编程

  详细介绍了Java中的垃圾分析算法,包括引用计数法和可达性分析算法的原理! 文章目录 1 垃圾收集概述2 引用计数算法3 可达性分析算法3.1 可以作为GC Roots对象种类3.2 两次标记4 方法区/永久代的垃圾分析 1 垃圾收集概述   在C/C++语言中,没有自动垃圾回收机制,是通过new关键字申请内存资源,通过del

JAVA垃圾回收--判断对象是否存活算法(引用计数法和可达性分析法)-爱代码爱编程

      JVM中的堆和方法区主要用来存放对象(方法区中也储存了一些静态变量和全局变量等信息),那么我们要使用GC算法对其进行回收时首先要考虑的就是该对象是否应该被回收。即判断该对象是否还有其他的引用或者关联使得该对象处于存活状态,我们需要将不在存活状态的对象标记出,以便GC回收。 一、引用计数法(reference-counting)      

jvm垃圾回收之引用计数算法和可达性分析算法(判断对象是否存活算法-爱代码爱编程

引用计数算法 在java中是通过引用来和对象进行关联的,也就是说如果要操作对象,必须通过引用来进行。那么很显然一个简单的办法就是通过引用计数来判断一个对象是否可以被回收。如果一个对象没有任何引用与之关联,则说明该对象基本不太可能在其他地方被使用到,那么这个对象就成为可被回收的对象了。这种方式成为引用计数法。 什么是引用计数算法:给对象

java 对象 清除_java学习笔记之对象清除、垃圾收集-爱代码爱编程

本篇来聊聊java中内存回收机制。 如果有c++编程经验的朋友,肯定知道在c++中如果创建了一个对象,当不再使用的时候,需要手动调用delete方法来进行销毁。那么在java中我们为什么可以自由的创建对象而不用去考虑(其实也是要考虑的,只是平常忽略了它)?因为java提供了一套完整的垃圾回收机制(gc)。它会自动扫描内存中我们所创建过且不再使用的对象

引用计数法和可达性分析算法-爱代码爱编程

垃圾回收算法分类两类 第一类算法判断对象生死算法,如引用计数法、可达性分析算法 ; 第二类收集死亡对象方法有四种,如标记-清除算法、标记-复制算法、标记-整理算法。 垃圾回收的区域:方法区,堆 引用计数法 栈中有对堆中的对象有引用,如果失去了这个引用关系,那么这个对象就需要被回收 在引用计数法中当一个对象被引用时,这个对象的的计数值+1,

【详解】GC如何判断一个对象是否需要被回收?引用计数法,可达性分析算法-爱代码爱编程

        在堆中存放着Java世界中几乎所有的对象实例,垃圾收集器在对堆进行回收前,第一件事就是确定哪些对象还存活着,哪些对象已经死去。         JVM垃圾回收机制中如何判断一个对象是否需要被回收呢?         JVM中给出了2种方法:引用计数法,可达性分析算法 (1)引用计数法         它是这样描述的:在一个对象中添加

深入理解java虚拟机-垃圾收集概述和判断对象是否该被回收_热爱生活の李的博客-爱代码爱编程

文章目录 概述垃圾收集器需要完成的三件事那些需要进行GC如何判断对象是否该被回收?引用计数法可达性分析算法引用生存还是死亡回收方法区 概述 垃圾收集器需要完成的三件事 那些内存需要回收? 什么时候回收? 如何回收? 那些需要进行GC 程序计数器、虚拟机栈、本地方法栈3个区域随线程而生,随线程灭而灭,栈中的栈帧随着方法的进

【jvm笔记】引用计数算法与可达性分析算法_可达性分析法的缺点-爱代码爱编程

目录 什么是垃圾 为什么需要GC 对象存活判断 引用计数算法 可达性分析算法 GC Roots 注意 什么是垃圾 垃圾是指在运行程序中没有任何指针指向的对象,这个对象就是需要被回收的垃圾 如果不及时对内存中的垃圾进行清理,那么,这些垃圾对象所占的内存空间会一直保留到应用程序结束,被保留的空间无法被其他对象使用,甚至可能导致内存

jvm虚拟机中如何判断对象可以回收_jvm中如何判断对象可以回收-爱代码爱编程

垃圾回收 如何判断对象可以回收一. 引用计数法二. 可达性分析算法三. 常见的5种引用1. 强引用2. 软弱引用① 软引用的应用② 软引用的引用队列③ 弱引用应用 3. 虚终引用

引用计数器法 可达性分析算法_jvm垃圾回收机制之对象回收算法-爱代码爱编程

前言 在前面的文章中,介绍了JVM内存模型分为:堆区、虚拟机栈、方法区、本地方法区和程序计数器,其中堆区是JVM中最大的一块内存区域,在Java中的所有对象实例都保存在此区域,它能被所有线程共享。 在Java中还有一个重要的机制:GC(垃圾收集器),堆是GC管理的主要区域,本文会带大家了解GC机制。 GC的简介 GC(Garbage

引用计数器法 可达性分析算法_面试官:你了解java中的四种引用嘛?-爱代码爱编程

每一种语言都有着自己操作内存元素的方式,C语言通过指针,而java就是通过引用。作为一门面向对象的语言,在java中世事万物皆对象。但是我们操作的标识符实际上是对象的一个引用(reference)。今天我们来分析一下java中的四种引用。 一、引用的历史 在Java中,我们的垃圾回收机制回收垃圾对象的时候就会依据对象的引用。比如说通过不同的垃