【JVM】 垃圾回收篇——自问自答(1)

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

Q什么是垃圾:
运行程序中,没用任何指针指向的对象。


Q为什么需要垃圾回收?
内存只分配,不整理回收,迟早会被消耗完。

内存碎片的整理,为新对象腾出空间

没有GC程序无法正常进行。


Q 哪些区域有GC,哪些区域会有OOM异常(错误)?

堆和方法区是线程共享的,存在GC 和OOM
堆有新生代和养老代,默认比例1:2 ,
新生代分为Eden :s0:s1 默认比例 8:1:1 (实际发现JDK8是6:1:1,一度怀疑是自适应策略,结果不是)
新生代中有YGC/MinorGC, 当Eden区满的时候触发,并使用复制算法,和分代策略,将Eden区和from区的存活对象 放到to区,如果存不下,就直接晋升老年代。
其余对象在对象头的分代阈值为15时晋升到老年代。

老年代垃圾回收为MajorGC,一般是老年代满的时候会被触发。为全堆回收

方法区若发生GC,为FUllGC,此时会对全堆以及方法区进行垃圾回收。

简单一句话:频繁收集年轻代,较少收集老年代,基本不动元空间。

PC寄存器 即没用GC 也没用OOM

虚拟机栈,无GC,有OOM 当栈的大小可以被动态扩容时,申请扩容的大小已经超过了内存可以支配空间,发生OOM,
StackOverFlowError,当栈空间大小是固定的,当前栈帧没有足够空间入栈了,此时方式 SOFERROR


Q:垃圾回收相关算法

标记阶段:引用计数和可达性分析算法。目的:判断对象的存活。


引用计数:
一个对象A,有一个引用计数器。当A被任何一个对象引用了,则A的计数器加1。引用失效,引用计数器则减1。
PS:什么叫A被一个对象引用了?举个例子。

class ReferenceClass{
    //static filed
  public static  A a =new A();
}
对象(new A()),被对象 ReferenceClass的静态变量引用,我们知道类变量的初始化是在类加载三部曲的初始化阶段<clint里>,随着类卸载而消亡。
若ReferenceClass类的生命周期不结束。对象(new A())就会一直被类变量a 引用着。
这里再发散:静态变量在逻辑上是存放在方法区的,从JDK7以后,静态变量和字符串常量池就存放在了堆空间中。

引用计数法有个缺陷:循环引用问题。
注意:java在标记阶段并没有使用引用计数算法。

在分析引用、对象等问题的时候。
一定要注意一个问题,这个引用到底是在方法中(局部变量),还是在类内的成员变量上
因为从内存解构上,局部引用是在虚拟机栈的局部变量表中的,而类内的成员变量引用,是在堆内的。

比如:
class  InstanceA{
    
    //此引用的位置是在对象内存解构中的
    Object ref =null;

    public static void main(String[] args){
        //这个引用,a1,是在局部变量表中的
        Instance a1 =new Instance();
        //这个ref 是在堆中,对象体内的
        a1.ref =a1;
        
        //操作数栈指向堆内对象的指针断开。a1.ref 是在堆内又指向自己。
        a1 =null; 
        
    }

}

Python使用的就是引用计数:解决循环引用的两个方法:
手动解除引用。
使用弱引用。

可达性分析算法:(追踪性垃圾收集)
首先要搞清楚,什么是GC Roots
GC roots 是一组集合,它包括:
1、虚拟机栈中的引用的对象
 比如 各个线程中被调用的方法中使用到的参数,局部变量等
 
2、本地方法栈引用的对象。


3、方法区静态属性引用的引用的对象。如上面的例子,A是引用类型的静态类型变量,它就是一个典型的GC root
class ReferenceClass{
    //static filed
  public static  A a =new A();
}

4、方法区中常量引用对象。
class Demo{

    String s ="abc";
    
    public void foo(){
     String ddd="XXXYYY"; //局部变量表最大slot深度为2,ddd为局部变量表中变量,XXXYYY在常量池中
    }

}

5、所有被同步锁持有的对象 同步监视器

6、java虚拟机内部的引用:
各种常驻对象,比如NUllPointerException,OOM,还有系统类加载器。基本数据类型的Class对象

关于Class对象的内存模型:

【JVM】 垃圾回收篇——自问自答(1),# JVM内存与垃圾回收篇,jvm,java,算法

7、根据不同的垃圾收集器以及当前回收区域不同,也会有一些临时性的GC roots对象加入。
比如使用G1回收器时,新生代的region里的对象,被老年代的某些对象所引用。此时,老年代的引用,就是临时的GC Roots
即指向某一堆内存中的对象的引用(指针),其本身与被引用对象不在一个回收的逻辑区内,它就是GC roots

为了保证GC roots的准确性,就需要在可达性分析时,内存是一个快照状态,而非运行时。保证其一致性。
此时就会产生STW stop the world。

   补问:Q 对象的finalization机制

对象终止机制:系统进行垃圾回收之前,会调用该对象的finalize()方法。
该方法是Object类所有,允许被子类所重写。用于在对象回收时进行资源释放,清理等操作。

但是注意,不要主动去调用某个对象的finalize方法,而是交给垃圾回收机制去调用(GC的finalizer守护线程)。

对象可能有三种状态:
可触及的:从根节点开始,可以到达这个对象
可复活的:无引用的对象,可以在 finalize()中复活。
不可触及的:对象的finalize()被调用,但是没用复活,此时对象为不可触及状态,finalize只能被调用一次

只有对象处于不可触及状态,才能被回收。

清除阶段:


标记-清除(mark-sweep)
注意,标记的不是垃圾,而是非垃圾(可达对象)。
两次遍历:
1、标记阶段,从根节点依次向下逐一遍历,找到所有的引用链。(递归遍历)
2、清除阶段 对堆内存从头至尾线性遍历,找到没用标记的对象,进行回收。

缺点:清理出来的空闲空间不连续,在新分配对象时候,内存分配采用空闲列表

复制算法:
原理和思路,就像我们理解的YGC的回收策略,Eden from to 来回倒腾。

注意点: 复制算法适合存活对象比较少的内存空间,如果对象过多,复制成本是很大的。
一般用在新生代回收

标记-压缩 mark-compact

在mark-sweep之后,进行了一次 压缩整理。
可以理解为mark-sweep-compact

其特点是 对象在发生了移动。
整理后,空闲区是规整的,新对象进行内存分配时候,可以进行指针碰撞,不再需要维护一个空闲列表

整体来说,复制算法最快,但是要移动对象,且浪费内存。
标记压缩速度最慢,且移动对象,但是空间开销很少,且没用内存碎片
标记清除速度中等,不需要移动对象,空间开销小,但是会产生一些内存碎片。

分代收集:
对不同生命周期的对象采取不同的收集方式,提高回收效率。
比如我们现在用的Hotspot虚拟机将对象分为:
年轻代
老年代


增量式收集:用户线程与GC线程并发执行,尽可能减少STW
其实仍是给予标记清除和 复制算法。允许垃圾收集线程以分阶段的方式,完成标记、清理或复制。
但是这样频繁进行线程和上下文切换,增大系统开销,降低系统吞吐量,而且并发执行,要处理好一致性问题,对垃圾与非垃圾要做进一步的修正标记。文章来源地址https://www.toymoban.com/news/detail-638434.html

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

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

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

相关文章

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

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

    2024年02月19日
    浏览(48)
  • 【Java虚拟机】JVM垃圾回收机制和常见回收算法原理

    1.垃圾回收机制 (1)什么是垃圾回收机制(Garbage Collection, 简称GC) 指自动管理动态分配的内存空间的机制,自动回收不再使用的内存,以避免内存泄漏和内存溢出的问题 最早是在1960年代提出的,程序员需要手动管理内存的分配和释放 这往往会导致内存泄漏和内存溢出等问

    2024年02月02日
    浏览(52)
  • 【Java高级应用:深入探索Java编程的强大功能,JVM 类加载机制, JVM 内存模型,垃圾回收机制,JVM 字节码执行,异常处理机制】

    本人详解 作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》 公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题 中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯 转载说明:务必注明来源(注明:作者:

    2024年01月16日
    浏览(89)
  • jvm垃圾回收及内存模型

    1、了解垃圾回收之前,必须先了解内存模型 jdk1.8后,元空间是 方法区的具体实现 (方法区是规范,之前叫永久代)   1)运行时常量池  就是字节码生成的Class对象包含上述的常量池       2、垃圾回收区域    a、 首先要标记垃圾,找出垃圾      b、Java垃圾回收(一)_java 垃

    2024年02月08日
    浏览(55)
  • java面经03-虚拟机篇-jvm内存结构&垃圾回收、内存溢出&类加载、引用&悲观锁&HashTable、引用&finalize

    要求 掌握 JVM 内存结构划分 尤其要知道方法区、永久代、元空间的关系 结合一段 java 代码的执行理解内存划分 执行 javac 命令编译源代码为字节码 执行 java 命令 创建 JVM,调用类加载子系统加载 class,将类的信息存入 方法区 创建 main 线程,使用的内存区域是 JVM 虚拟机栈 ,

    2024年02月09日
    浏览(56)
  • JVM之内存与垃圾回收篇2

    PC Register是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError的区域。 为什么要有PC寄存器? 因为CPU会在不同的线程之间来回切换,切换回来之后,需要知道接着从哪里开始执行。 JVM字节码解释器需要通过改变PC寄存器中的值来明确下一条应该执行什么样的字节码指令。

    2024年02月17日
    浏览(50)
  • JVM学习之内存与垃圾回收篇1

    2000年,JDK 1.3发布,Java Hot Spot Virtual Machine正式发布,成为Java的默认虚拟机。 2006年,JDK 6发布。同年,Java开源并建立了OpenJDK。顺理成章,Hotspot虚拟机也成为了OpenJDK中的默认虚拟机。 2008年,Oracle收购了BEA,得到了JRockit虚拟机。 2010年,Oracle收购了Sun,获得了Java的商标和Ho

    2024年02月16日
    浏览(58)
  • JVM—内存管理(运行时数据区)、垃圾回收

    当JVM类加载器加载完字节码文件之后,会交给执行引擎执行,在执行的过程中会有一块JVM内存区域来存放程序运行过程中的数据,也就是我们图中放的运行时数据区,那这一块运行时数据区究竟帮我们做了哪些工作?我们常说的线上内存泄漏和内存溢出是因为什么?我们今儿

    2024年02月13日
    浏览(40)
  • 【JVM】JVM 垃圾回收算法

    目前JVM中有三种常见的垃圾回收算法,分别是:标记清除、标记整理和复制,这三种垃圾回收算法各有优缺点,下面逐一介绍。 在读本篇文章中,如果对JVM中哪个是垃圾,哪个不是垃圾,JVM到底是怎么知道的,请先读下面这篇文章 【JVM】JVM 判断对象存活算法(引用计数算法

    2024年02月09日
    浏览(52)
  • JVM 垃圾回收详解之内存分配和回收原则+死亡对象判断方法

    当需要排查各种内存溢出问题、当垃圾收集成为系统达到更高并发的瓶颈时,我们就需要对这些“自动化”的技术实施必要的监控和调节。 Java 的自动内存管理主要是针对对象内存的回收和对象内存的分配。同时,Java 自动内存管理最核心的功能是 堆 内存中对象的分配与回收

    2023年04月19日
    浏览(58)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包