【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对象的内存模型:

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
其实仍是给予标记清除和 复制算法。允许垃圾收集线程以分阶段的方式,完成标记、清理或复制。
但是这样频繁进行线程和上下文切换,增大系统开销,降低系统吞吐量,而且并发执行,要处理好一致性问题,对垃圾与非垃圾要做进一步的修正标记。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

esp8266使用arduinoJson与tft_espi库发生冲突解决方法

esp8266使用arduinoJson与tft_espi库发生冲突解决方法 arduinoJson与tft_espi库发生冲突解决方法下载arduinoJson5.0版本的&#xff0c;不要用最新版本 示范代码&#xff1a; // Copyright Benoit Blanchon 2014 // MIT License // // Arduino JSON library // https://git…

springboot mongo 使用

nosql对我来说&#xff0c;就是用它的变动列&#xff0c;如果列是固定的&#xff0c;我为什么不用mysql这种关系型数据库呢&#xff1f; 所以&#xff0c;现在网上搜出来的大部分&#xff0c;用实体类去接的做法&#xff0c;并不适合我的需求。 所以&#xff0c;整理记录一下…

【资料分享】全志科技T507-H工业核心板规格书

1 核心板简介 创龙科技SOM-TLT507是一款基于全志科技T507-H处理器设计的4核ARM Cortex-A53全国产工业核心板&#xff0c;主频高达1.416GHz。核心板CPU、ROM、RAM、电源、晶振等所有元器件均采用国产工业级方案&#xff0c;国产化率100%。 核心板通过邮票孔连接方式引出MIPI C…

Winform中DatagridView 表头实现一个加上一个checkBox,实现全选选项功能

实现效果 点击checkBox1或者直接在第一列列表头点击即可实现 代码实现 我的datagridview叫dgv 我在datagridview已经默认添加了一个DataGridViewCheckBoxColumn&#xff0c;勾选时value为1&#xff0c;不勾选时value为0 第一种通过可视化拖动一个checkBox来实现 拖动组…

IC岗位详解| 高薪模拟版图工程师需要掌握哪些技能?

IC模拟版图设计在IC行业中是门槛相对较低的一个岗位&#xff0c;其他岗位大都要求是科班毕业&#xff0c;或者是硕士以上学历&#xff0c;IC模拟版图设计本科生也很好入门&#xff0c;对于基础差的同学这是非常好的一个入门机会。 模拟版图工程师介绍 模拟版图设计工程师为专…

爬虫如何应对网站的反爬机制?如何查找user-agent对应的值

import requestsurl https://movie.douban.com/top250 response requests.get(url) # 查看结果 print(response)在requests使用一文中我们有讲到&#xff0c;当状态码不是200时表示爬虫不可用&#xff0c;也就是说我们获取不到网页源代码。但是我们还是可以挣扎一下&#xff…

以商业大数据技术助力数据合规流通体系建立,合合信息参编《数据经纪从业人员评价规范》团标

经国务院批准&#xff0c;由北京市人民政府、国家发展和改革委员会、工业和信息化部、商务部、国家互联网信息办公室、中国科学技术协会共同主办的2023 全球数字经济大会于近期隆重召开。由数交数据经纪&#xff08;深圳&#xff09;有限公司为主要发起单位&#xff0c;合合信息…

SpringBoot多环境切换及JSR303数据校验

多环境切换 profile是Spring对不同环境提供不同配置功能的支持&#xff0c;可以通过激活不同的环境版本&#xff0c;实现快速切换环境&#xff1b; 多配置文件 我们在主配置文件编写的时候&#xff0c;文件名可以是 application-{profile}.properties/yml , 用来指定多个环境版…

美国访问学者签证怎么样申请成功率高?

近年来&#xff0c;越来越多的人选择申请美国访问学者签证&#xff0c;以便在美国深造、交流学术知识以及拓展国际视野。那么&#xff0c;如何提高申请美国访问学者签证的成功率呢&#xff1f;以下是知识人网小编整理的一些成功申请的建议供您参考。 1.提前准备&#xff1a;提交…

HTML笔记(2)

列表标签 项目标识符&#xff08;项目符号&#xff09;一般是不需要的 代码演示 改变符号样式&#xff0c;type属性 表格标签 代码演示 练习案例 布局标签 div是块儿级标签&#xff0c;占一整行&#xff1b; span标签不会占一整行&#xff0c;它只占包裹内容的那块儿区域&a…

小程序wx:else提示 Bad attr `wx

问题&#xff1a;以下wx:for里的wx:if &#xff0c; wx:else 会报这个错&#xff1a;Bad attr wx <scroll-view class"scroll1" scroll-x enable-flex"true"><view wx:if"{{playlist.length>0}}" class"item" wx:for"…

nginx基于源码安装的方式对静态页面、虚拟主机(IP、端口、域名)和日志文件进行配置

一.静态页面 1.更改页面内容 2.更改配置文件 3.测试 二.虚拟主机配置 1.基于IP &#xff08;1&#xff09;在html目录下新建目录存放测试文件 &#xff08;2&#xff09;修改nginx.conf文件&#xff0c;在htttp模块中配置两个server模块分别对应两个IP &#xff08;3&am…