iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Java jvm垃圾回收详解
  • 244
分享到

Java jvm垃圾回收详解

2024-04-02 19:04:59 244人浏览 八月长安

Python 官方文档:入门教程 => 点击学习

摘要

目录常见面试题1.JVM内存回收和分配1.1主要的区域?GC测试1.2大对象进入老年代1.3长期存活的对象进入老年代1.4主要进行gc的区域gc的类型Young GcFull Gc1

常见面试

  • 如何判断对象是否死亡
  • 简单介绍一下强引用、软引用、弱引用、虚引用
  • 如何判断常量是一个废弃常量
  • 如何判断类是一个无用类
  • 垃圾收集有哪些算法、各自的特点?
  • 常见的垃圾回收器有哪些?
  • 介绍一下CMS,G1收集器?
  • minor gc和full gc有什么不同呢?

image-20211022150704627

1.JVM内存回收和分配

1.1主要的区域?

  • 在伊甸区先产生对象
  • 然后发生一次gc之后去到幸存区幸存区
  • 如果年龄大于阈值那么就会升级到老年代

阈值的计算

如果某个年龄段的大小大于幸存区的一半,那么就取阈值或者是这个年龄最小的那个作为新的阈值升级到老年代

  • gc的时候是幸存区的from和伊甸区的存活对象复制到to,然后再清理其它的对象,接着from和to就会交换指针

gc测试

场景就是先给eden分配足量的空间,然后再申请大量空间,问题就是幸存区的空间不够用

  • 那么这个时候就会触发分配担保机制,把多余的对象分配到老年代,而不会触发full gc。仍然还是monor gc

public class GCTest {
    public static void main(String[] args) {
        byte[] allocation1, allocation2;
        allocation1 = new byte[50900*1024];
        allocation2 = new byte[9500*1024];
    }
}

image-20211022151130599

1.2大对象进入老年代

  • 防止在标记复制的时候占用大量的时间,降低gc的效率

1.3长期存活的对象进入老年代

  • 每次gc都会把eden和from的存活对象放到to,每次gc存活年龄就会+1,如果超过阈值那么就能够升级到老年代,设置的参数是-XX:MaxTenuringThreshold
  • 下面是计算的方式,每个年龄的人数累加,累加一个就+1,如果对象数量大于幸存区的一半的时候就需要更新阈值(新计算的age和MaxTenuringThreshold)
  • 通常晋升阈值是15,但是CMS是6

uint ageTable::compute_tenuring_threshold(size_t survivor_capacity) {
    //survivor_capacity是survivor空间的大小
    size_t desired_survivor_size = (size_t)((((double)survivor_capacity)*TargetSurvivorRatio)/100);
    size_t total = 0;
    uint age = 1;
    while (age < table_size) {
        //sizes数组是每个年龄段对象大小
        total += sizes[age];
        if (total > desired_survivor_size) {
            break;
        }
        age++;
    }
    uint result = age < MaxTenuringThreshold ? age : MaxTenuringThreshold;
    ...
}

1.4主要进行gc的区域

gc的类型

  • Partial Gc

Young Gc:收集新生代的

Old Gc:只收集老年代的

Mixed Gc:新生代和部分老年代

  • Full Gc:新生代,老年代都会收集

Young Gc

  • 每次都是收集新生代的,并且晋升那些存活久的

Full Gc

  • 如果发现幸存区要晋升的对象内存空间比老年代内存空间更大那么就进行full Gc。有的虚拟机会先进行young gc来清理掉一些,减少full gc的时间消耗

1.5空间分配担保?

  • jdk1.6之前需要判断老年代剩余的空间是不是完全大于新生代的空间,如果是那么才能进行minorgc保证不会出现问题。如果是不行就会去检查-XX:handlePromotionFailure也就是晋升的对象平均大小是不是小于老年代剩余空间,如果是那么就直接minor gc否则就full gc
  • jdk1.6之后直接检查新生代晋升平均大小如果小于老年代那么就会直接晋升

2.对象已经死亡?

image-20211022155926623

2.1引用计数法

  • 其实就是每次被引用那么计数+1,如果计数不是0那么就不会被回收
  • 但是不使用的原因就是循环引用依赖,如果两个对象互相引用就会导致计数永远不会为0

2.2可达性分析

  • Gc roots作为起点一直往下面的一条引用链

gc Roots的对象

  • 虚拟机栈引用的对象(栈的本地局部变量表)
  • 本地方法栈引用的对象
  • 方法区常量引用的对象(常量池引用的对象)
  • 方法区静态属性引用的对象
  • 被同步持有的对象
  • java虚拟机内部引用,比如Integer这些基本类型的

image-20211022160419101

2.3再谈引用

  • 强引用:垃圾回收器不会对他进行回收
  • 软引用:内存空间不足会回收
  • 弱引用:gc就回收
  • 虚引用:随时会被回收而且需要引用队列

虚引用、软引用、弱引用的区别?

  • 虚引用的对象在gc之前会被送到引用队列,并且程序在对象回收之前做相应的活动(临死之前的处理)
  • 软引用是用的最多的,可以提高gc的效率,维护系统安全,防止内存溢出

2.4不可达对象不一定回收

  • 在回收之前会对对象进行一次标记,看是否会执行finalize方法。如果没有那么这些对象将会先被回收
  • 如果有那么进行第二次标记,让对象执行finalize之后再进行回收

2.5如何判断一个常量是废弃常量?

  • 如果常量池对象没有被任何对象引用就会被回收
  • jdk1.7之前运行时常量池包含字符串常量池,需要进行复制来返回新的引用(堆有一个,常量池有一个)
  • jdk1.7的时候字符串池已经不在运行时常量池,如果调用intern就会把当前对象放入常量池并且返回引用(只有常量池有一个)。如果本来就存在就会返回对象实例的地址。
  • jdk1.8之后运行时常量池已经转移到了元空间

2.6如果判断一个类没有用?

  • 类的实例都回收了
  • 类的类加载器回收了
  • 类信息没有被引用
  • 大量的反射和动态代理生成类信息会对方法区产生很大的压力

3.垃圾回收算法

hotspot为什么要区分老年代和新生代?

原因就是不同的存活对象需要不同的垃圾回收算法

  • 如果新生代用的是标记整理,问题就是每次清除大量的对象,移动时间很长,整理消耗很大。但是标记复制就很快,因为存活对象少
  • 但是老年代如果使用标记整理就很好,因为存活多移动少,复制就相反
  • 不能够统一设计为弱分代假说和强分代假说

跨代收集假说?

如果老年代和新生代互相引用,新生代的年龄就会被拉长。但是为了知道新生代什么时候被gc,这个时候可以给新生代加上一个记忆集(把老年代划分为很多个格子,代表谁引用了我),避免扫描整个老年代

4.垃圾回收器

4.1Serial收集器

  • 线程收集器,每次都要阻塞其它线程(STW),一个垃圾线程单独回收
  • 新生代是标记复制,老年代是标记整理
  • 它简单高效,没有和其它线程交换不会产生并发问题
  • 但是STW会导致响应很慢

4.2ParNew收集器

  • Serial的多线程版本,但是还是会STW
  • 新生代是标记复制,老年代是标记整理

4.3Parallel Scavenge收集器

  • 新生代是标记复制,老年代是标记整理
  • 和ParNew不同的地方就是它完全关注cpu的利用率,也就是处理任务的吞吐量,而不会管STW到底停多久

4.4SerialOld

  • Serial的老年代版本,1.5以前和Parallel Scavenge一起使用,还有别的用途就是CMS的后备方案

4.5Parallel Old收集器

  • Parallel Scavenge收集器的老年代也是注重吞吐量

4.6CMS收集器

  • 注重最小响应时间
  • 垃圾收集器和用户线程同时工作
  • 初始标记记录gc root直接相连的对象
  • 并发标记遍历整个链,但是可以和用户线程并发运行
  • 重新标记修正那些更新的对象的引用链,比并发标记短
  • 并发清除

问题?

内存碎片多对cpu资源敏感

image-20211022163933970

4.7G1收集器

同时满足响应快处理多的问题

特点

  • 并行和并发,使用多个cpu执行gc线程来缩短stw,而且还能与java线程并发执行
  • 分代收集
  • 空间整合:大部分时候使用标记复制
  • 可预测停顿:响应时间快,可以设置stw时间
  • 分区之间的跨代引用,young这里使用了rset(非收集区指向收集区)记录,老年代那个区域指向了我,老年代使用了卡表划分了很多个区域,那么minor gc的时候就不需要遍历整个其它所有区域去看看当前的区域的对象到底有没有被引用。

image-20211022192746263

补充字符串池的本质

第一个问题是String a="a"的时候做了什么?

  • 先去找常量池是否存在a如果存在那么就直接返回常量池的引用地址返回,如果不存在那么就创建一个在常量池然后再返回引用地址

第二个问题new String(“a”)发生了什么?

  • 先看看常量池是否存在a,如果不存在创建一个在常量池,而且在堆单独创建一个a对象返回引用(而不是返回常量池的),相当于就是创建了两次。
  • 如果第二次创建发现已经存在就直接在堆中创建对象。

第三个问题intern的原理?

  • 看看常量池有没有这个字符串,没有就创建并返回常量池对象的地址引用
  • 如果有那么直接返回常量池对象的地址引用

String s1=new String(“a”)

String s2=s1.intern();

很明显s1不等于s2如果上面的问题都清晰知道。s1引用的是堆,而s2引用的是常量池的

第四个问题

String s3=new String(“1”)+new String(“1”);

String s5=s3.intern();

String s4=“11”

那么地方他们相等吗?当然是相等的,s3会把1存入常量池,但是不会吧11存入常量池因为,还没编译出来。调用了intern之后才会把对象存入常量池,而这个时候存入的对象就是s3指向的那个。所以s4指向的也是s3的。如果是s0="11"的话那就不一样了,s3.intern只会返回常量池的对象引用地址,而不是s3的,因为s3是不能重复intern 11进去的。jdk1.6的话那么无论怎么样都是错的,intern是复制一份,而不是把对象存入常量池(因为字符串常量池在方法区,而jdk1.7它在堆所以可以很好的保存s3的引用)

下面的代码正确分析应该是三个true,但是在test里面就会先缓存了11导致false, true,false的问题。


@Test
public void test4(){
    String s3 = new String("1") + new String("1");
    String s5 = s3.intern();
    String s4 = "11";
    System.out.println(s5 == s3);
    System.out.println(s5 == s4);
    System.out.println(s3 == s4);
    System.out.println("======================");
    String s6 = new String("Go") +new String("od");
    String s7 = s6.intern();
    String s8 = "good";
    System.out.println(s6 == s7);
    System.out.println(s7 == s8);
    System.out.println(s6 == s8);
}

finalize的原理

  • 其实就是对象重写了finalize,那么第一次gc的时候如果发现有finalize,就会把对象带到F-Queue上面等待,执行finalize方法进行自救,下面就是一个自救过程,new了一个GCTest对象,这个时候test不引用了,那么正常来说这个GCTest就会被回收,但是它触发了finalize的方法,最后再次在finalize中使用test引用它所以对象没有被消除
  • 但是finalize是一个守护线程,防止有的finalize是个循环等待方法阻塞整个队列,影响回收效率
  • 最后一次标记就是在F-queue里面标记这个对象(如果没有引用)然后释放
  • finalize实际上是放到了Finalizer线程上实现。然后然引用队列指向这个双向链表,一旦遇到gc,那么就会调用ReferenceHandler来处理这些节点的finalize调用,调用之后断开节点,节点就会被回收了
  • finalize上锁导致执行很慢

public class GCTest {
    static GCTest test;
    public void isAlive(){
        System.out.println("我还活着");
    }
    @Override
    protected void finalize() throws Throwable {
        System.out.println("我要死了");
        test=this;
    }
    public static void main(String[] args) throws InterruptedException {
       test = new GCTest();
        test=null;
        System.gc();
        Thread.sleep(500);
        if(test!=null){
            test.isAlive();
        }else{
            System.out.println("死了");
        }
        test=null;
        System.gc();
        if(test!=null){
            test.isAlive();
        }else{
            System.out.println("死了");
        }
    }
}

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注编程网的更多内容!

--结束END--

本文标题: Java jvm垃圾回收详解

本文链接: https://www.lsjlt.com/news/155507.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java jvm垃圾回收详解
    目录常见面试题1.JVM内存回收和分配1.1主要的区域?gc测试1.2大对象进入老年代1.3长期存活的对象进入老年代1.4主要进行gc的区域gc的类型Young GcFull Gc1...
    99+
    2024-04-02
  • JVM垃圾回收器详解
    这篇文章主要介绍“JVM垃圾回收器详解”,在日常操作中,相信很多人在JVM垃圾回收器详解问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”JVM垃圾回收器详解”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!1 ...
    99+
    2023-06-02
  • JVM垃圾回收——G1垃圾收集器
    目录 一、什么是G1垃圾收集器 二、G1垃圾收集器的内存划分 三、G1垃圾收集器的收集过程  四、G1收集器的优缺点 五、G1收集器的JVM参数配置 一、什么是G1垃圾收集器         Garbage First(简称G1)收集...
    99+
    2023-10-25
    jvm java G1
  • 最新JVM垃圾回收算法详解
    目录1.垃圾回收需要做什么2.如何判断对象可被回收2.1 引用计数算法2.1.2 优点2.1.2 缺点2.2 可达性分析算法2.2.1 算法思路2.2.2 GC Roots对象(两栈...
    99+
    2024-04-02
  • jvm垃圾回收算法详细解析
    目录前言几种常用的垃圾回收算法1、引用计数法2、根搜索算法3、标记清除法(Mark-Sweep)4、复制交换算法(Mark-Sweep)5、标记压缩算法(Mark-Compact)J...
    99+
    2024-04-02
  • GC参考手册jvm垃圾回收详解
    1,什么是垃圾回收? 顾名思义,垃圾收集(Garbage Collection)的意思就是 —— 找到垃圾并进行清理。但现有的垃圾收集实现却恰恰相反: 垃圾收...
    99+
    2024-04-02
  • java 垃圾回收机制以及经典垃圾回收器详解
    判断对象存活方法 引用计数法:在对象中添加一个引用计数子,每当一个地方引用他时,计数器就加一,当引用失效时,计数器就减一。 会有对象循环引用问题: objA.instance =...
    99+
    2024-04-02
  • JVM类加载,垃圾回收
    目录类加载子系统双亲委派模型垃圾回收判断对象已死JDK1.2之后的四种引用类型:1.强引用:2.软引用:3.弱引用:4.虚引用:常见的垃圾回收算法:1.标记–清除算法:(Mark–S...
    99+
    2024-04-02
  • 新手入门Jvm--Jvm垃圾回收
    目录1. Jvm垃圾回收2. 作用域3. 分类4. 垃圾回收算法4.1 标记-复制算法4.2 标记-清除算法4.3 标记-整理算法5. 垃圾收集器5.1 Serial收集器(-XX:...
    99+
    2024-04-02
  • JVM的垃圾回收机制详解与调优
    这篇文章主要讲解了“JVM的垃圾回收机制详解与调优”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“JVM的垃圾回收机制详解与调优”吧!JVM的gc概述gc即垃圾收集机制是指jvm用于释放那些不...
    99+
    2023-06-03
  • 详解 Java性能优化和JVM GC(垃圾回收机制)
    Java的性能优化,JVM GC(垃圾回收机制)在学习Java GC 之前,我们需要记住一个单词:stop-the-world 。它会在任何一种GC算法中发生。stop-the-world 意味着JVM因为需要执行GC而停止了应用程序的执行...
    99+
    2023-06-02
  • JVM基本垃圾回收算法
    这篇文章主要介绍“JVM基本垃圾回收算法”,在日常操作中,相信很多人在JVM基本垃圾回收算法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”JVM基本垃圾回收算法”的疑惑有所帮助!接下来,请跟着小编一起来学习吧...
    99+
    2023-06-17
  • JVM垃圾回收器有哪些
    这篇文章主要介绍“JVM垃圾回收器有哪些”,在日常操作中,相信很多人在JVM垃圾回收器有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”JVM垃圾回收器有哪些”的疑惑有所帮助!接下来,请跟着小编一起来学习吧...
    99+
    2023-06-05
  • 深入理解JVM垃圾回收算法
    目录一、垃圾标记阶段1.1、引用计数法(java没有采用)1.2、可达性分析算法二、对象的finalization机制2.1、对象是否"死亡"三、使用(MAT与JProfiler)工...
    99+
    2024-04-02
  • Java的垃圾回收机制详解
    目录 1、C语言与Java语言垃圾回收区别 2、System.gc() 3、面试题引入Java垃圾回收 3.1 jvm怎么确定哪些对象应该进行回收 3.1.1 引用计数法 3.1.2 可达性分析算法  3.2 jvm会在什么时候进行垃圾回收...
    99+
    2023-09-13
    java jvm 开发语言
  • 快速理解Java垃圾回收和jvm中的stw
    Java中Stop-The-World机制简称STW,是在执行垃圾收集算法时,Java应用程序的其他所有线程都被挂起(除了垃圾收集帮助器之外)。Java中一种全局暂停现象,全局停顿,所有Java代码停止,native代码可以执行,但不能与J...
    99+
    2023-05-31
    java jvm ava
  • JVM垃圾回收器是什么
    这篇文章主要讲解了“JVM垃圾回收器是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“JVM垃圾回收器是什么”吧!并发与并行并行(Parallel):并行描述的是多条垃圾收集器线程之间的关...
    99+
    2023-07-02
  • 有哪些jvm垃圾回收算法
    这篇文章将为大家详细讲解有关有哪些jvm垃圾回收算法,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。jvm垃圾回收算法:1、“标记–清除”算法;首先标记出所有需要被回收的对象,然后在标记完成后...
    99+
    2023-06-14
  • Java 中的垃圾回收机制详解
    目录介绍重要条款:使对象符合 GC 条件的方法请求JVM运行垃圾收集器的方式定稿总结介绍 在 C/C++ 中,程序员负责对象的创建和销毁。通常程序员会忽略无用对象的销毁。由...
    99+
    2024-04-02
  • JVM的垃圾回收机制你了解吗
    目录一:回收堆内存1.如何判定对象已死(可达性分析算法)2.对象的引用级别 3.对象的死亡过程二:垃圾回收算法1.标记清除算法2.标记复制算法3.标记整理算法三:垃圾收集器...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作