JVM垃圾回收总结

news2025/4/9 22:49:14

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


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];
    }
}


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.5主要进行gc的区域
gc的类型
Partial Gc
Young Gc:收集新生代的
Old Gc:只收集老年代的
Mixed Gc:新生代和部分老年代
Full Gc:新生代,老年代都会收集
Young Gc
每次都是收集新生代的,并且晋升那些存活久的
Full Gc
如果发现幸存区要晋升的对象内存空间比老年代内存空间更大那么就进行full Gc。有的虚拟机会先进行young gc来清理掉一些,减少full gc的时间消耗
1.6空间分配担保?
jdk1.6之前需要判断老年代剩余的空间是不是完全大于新生代的空间,如果是那么才能进行minorgc保证不会出现问题。如果是不行就会去检查-XX:handlePromotionFailure也就是晋升的对象平均大小是不是小于老年代剩余空间,如果是那么就直接minor gc否则就full gc
jdk1.6之后直接检查新生代晋升平均大小如果小于老年代那么就会直接晋升
2.对象已经死亡?

 


2.1引用计数法
其实就是每次被引用那么计数+1,如果计数不是0那么就不会被回收
但是不使用的原因就是循环引用依赖,如果两个对象互相引用就会导致计数永远不会为0
2.2可达性分析
Gc roots作为起点一直往下面的一条引用链
gc Roots的对象

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


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资源敏感


4.7G1收集器
同时满足响应快处理多的问题
特点
并行和并发,使用多个cpu执行gc线程来缩短stw,而且还能与java线程并发执行

 分代收集

空间整合:大部分时候使用标记复制

可预测停顿:响应时间快,可以设置stw时间

分区之间的跨代引用,young这里使用了rset(非收集区指向收集区)记录,老年代那个区域指向了我,老年代使用了卡表划分了很多个区域,那么minor gc的时候就不需要遍历整个其它所有区域去看看当前的区域的对象到底有没有被引用。

补充字符串池的本质
第一个问题是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("死了");
        }

    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/29384.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[附源码]计算机毕业设计JAVA课后作业提交系统关键技术研究与系统实现

[附源码]计算机毕业设计JAVA课后作业提交系统关键技术研究与系统实现 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&am…

[附源码]计算机毕业设计JAVA课堂点名系统

[附源码]计算机毕业设计JAVA课堂点名系统 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis M…

【2】Anaconda基本命令以及相关工具:jupyter、numpy、Matplotilb

上一篇请移步【1】Anaconda基本命令以及相关工具&#xff1a;jupyter、numpy、Matplotilb_水w的博客-CSDN博客 目录 3 Numpy数组基础索引&#xff1a;索引和切片 ◼ 基础索引 4 Numpy非常重要的数组合并与拆分操作 ◼ 数组的合并-concatenate、vstack、hstack numpy.vstac…

生产制造管理:供应商管理系统

随着经济全球化和信息技术的快速推进发展&#xff0c;传统的管理模式早已不再适应现代市场竞争与生产制造的需要&#xff0c;以顾客需求为中心的供应链管理显得更为重要。供应链是围绕核心企业&#xff0c;通过对信息流、物流、资金流等关键部分的控制连成一个整体的功能网链结…

期末前端web大作业——我的家乡陕西介绍网页制作源码HTML+CSS+JavaScript

家乡旅游景点网页作业制作 网页代码运用了DIV盒子的使用方法&#xff0c;如盒子的嵌套、浮动、margin、border、background等属性的使用&#xff0c;外部大盒子设定居中&#xff0c;内部左中右布局&#xff0c;下方横向浮动排列&#xff0c;大学学习的前端知识点和布局方式都有…

[附源码]计算机毕业设计JAVA科院垃圾分类系统

[附源码]计算机毕业设计JAVA科院垃圾分类系统 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybati…

Flutter For Web——一个简单的图片素材网站

一个简单的图片素材网站效果视频登录注册页效果图UI初始化TabBarPageView组合登录账号输入按键处理SharedPreferences封装保存数据取出数据清除缓冲内容搜索栏效果图UI首页效果图UIDio网络请求Dio单例封装构造Dio对象GetPostResponse使用解析Json图片阅览UIDialog下载UI调用浏览…

Spring之IOC 为什么能解耦

1.1 什么是IOC &#xff08;1&#xff09;控制反转&#xff0c;把对象的创建和对象之间的调用过程&#xff0c;都交给Spring进行管理 &#xff08;2&#xff09;使用IOC目的&#xff1a;为了耦合性降低 1.2 IOC的底层原理 &#xff08;1&#xff09;使用的技术&#xff1a;…

完美解决-RuntimeError: CUDA error: device-side assert triggered

网上的解决方案意思是对的&#xff0c;但并没有给出相应的实际解决方法&#xff1a; 问题描述&#xff1a; 当使用ImageFolder方式构建数据集的时候&#xff1a; train_data torchvision.datasets.ImageFolder(train_path, transformtrain_transform)train_loader DataLoad…

学习Git看这一篇就够了

文章目录Git简单介绍官方网址Git是什么版本控制系统的演化Git安装 - Windows版需要熟悉的几个Linux命令Git命令行状态对应目录位置Git命令1. git init2. git status3. git add4. git commit5. git config6. git reset7. git diff练习 - 创建学生管理系统练习提交代码练习修改代…

传感模块:MATEKSYS Optical Flow LIDAR 3901-L0X

传感模块&#xff1a;MATEKSYS Optical Flow & LIDAR 3901-L0X1. 模块介绍2. 规格参数3. 使用方法Step1: 接线方式Step2: 安装方式Step3: 使用范围4. 存在问题4.1 MATEKSYS 3901-L0X 输出协议格式&#xff1f;4.1.1 支持光流计协议(iNav-CXOF)4.1.2 支持光流计激光测距协议…

混合SDN中的安全性问题研究

混合SDN中的安全性问题研究混合SDN中的安全性问题研究1.学习目标2.学习内容3.目前存在的问题4.解决办法1.关于欺骗ARP的讨论2.DDoS攻击探讨5.解决方案现有文献的解决方案6.目前面临的挑战申明&#xff1a; 未经许可&#xff0c;禁止以任何形式转载&#xff0c;若要引用&#xf…

美食杰项目(一)登录注册页

目录前言&#xff1a;具体效果&#xff1a;代码思路相应的组件&#xff1a;具体代码&#xff1a;all页面的具体代码&#xff1a;login页面具体代码&#xff1a;**登录和注册的基本功能都一样所以没有注释**enroll页面的具体代码&#xff1a;路由相关代码&#xff1a;相关引入&a…

Swagger2依赖的版本问题导致其配置文件一直报错的终极解决方案

Swagger2依赖的版本问题 在项目中使用的报错的版本 springboot2.2.1.RELEASE swagger2.9.2导致在写swagger的配置类时&#xff0c;一直引入不了依赖 导入正确的依赖 <!--swagger--> <dependency><groupId>io.springfox</groupId><artifactId>sp…

JIRA on K8s helm部署实战

JIRA on K8s helm部署实战jira on k8s实战waht&#xff1f;架构![在这里插入图片描述](https://img-blog.csdnimg.cn/7b007d9bfb4648c7b1ab816105f51701.png)如何选择chart官方的chartmox 的chart【1】mox chart 安装脚本【2】生产环境的yamljira 的sharedHome 和localHome 的区…

spring源码 - @Condition原理及运用

1.在源码中&#xff0c;在生成beanfinition中有有如一段代码 以下代码逻辑中执行this.conditionEvaluator.shouldSkip返回true直接跳出beandefinition生成逻辑 private <T> void doRegisterBean(Class<T> beanClass, Nullable String name,Nullable Class<? …

实验数据处理

来源 加热冷却温度实验&#xff0c;相同实验参数可能有一次或多次重复实验&#xff0c;一次实验中也可能有多次。如何分别每一次周期&#xff0c;并把每个周期的数据都分析出来&#xff0c;成为一个问题。 解决思想 想根据冷却后的平台划分不同周期&#xff0c;但是由于冷却…

web前端期末大作业【仿12306铁路官网首页】学生网页设计作业源码

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

分享5款同类软件中的翘楚,属于是WIN10必备良品

今天要给大家推荐的是5款软件&#xff0c;每个都是同类软件中的个中翘楚,请大家给我高调地使用起来,不用替我藏着掖着。 1.PPT插件——OneKeyTools OK插件是一款免费的PPT插件&#xff0c;让你的PPT制作有无限可能&#xff01;它的功能&#xff0c;太多了&#xff0c;比如图片…

Apache HTTPD 换行解析漏洞(CVE-2017-15715)

漏洞环境 Vulhub 影响版本 Apache 2.4.0~2.4.29 漏洞简介 Apache HTTPD 是一款 HTTP 服务器&#xff0c;其 2.4.0~2.4.29 版本中存在一个解析漏洞&#xff0c;在解析 PHP 时&#xff0c;1.php\x0A 将被按照 PHP 后缀进行解析。 解析漏洞是指服务器应用程序会把某些人为构造…