02JVM_垃圾回收GC

二、垃圾回收GC

里面存放着java的所有对象实例,当对象为“死去”,也就是不再使用的对象,就会进行垃圾回收GC

1.如何判断对象可以回收

1.1引用计数器

介绍

在对象中添加一个引用计数器,当一个对象被其他变量引用时这个对象的引用计数器加1。当某个变量不再引用这个对象时引用计数器减1。当这个引用计数变为0时,这个对象就会被垃圾回收。

优点

判定效率很高

缺点

不完全准确,当两个对象相互引用就判断失效了。当A引用B对象,B引用A对象,然后A和B不再被其他变量引用,垃圾不会回收,出现了垃圾回收失效。

1.2可达性分析算法(Java)

介绍

①要确定一个根对象GC Roots(肯定不会被垃圾回收的对象)作为起始节点,当垃圾回收前会对堆对象进行扫描,判断这些对象是否被根对象引用,如果没有被引用那么这个对象就可以垃圾回收。

②java虚拟机是通过可达性分析判断存活对象

哪些对象可以作为GC Root?

①虚拟机栈中引用的对象

各个线程调用的方法(参数,局部变量)

②本地方法栈中native方法引用的对象

③方法区中类静态属性引用的对象

Java类的引用类型静态变量

④方法区中常量引用的对象

字符串常量池StringTable里的引用

⑤所有被同步锁synchronized持有的对象

⑥java虚拟机内部的引用,核心类

1.3四种引用

1.强引用-不回收

介绍

程序代码中普遍存在的引用赋值“Object obj = new Object()”这种引用关系。

特点

不回收,只要沿着GC Root引用链能够找到这个对象,这个对象就不会被垃圾回收。

2.软引用-内存不足回收

介绍

软引用(间接引用)是一些还有用但非必需的对象,当被软引用关联的对象,系统发生内存溢出钱,会把这些对象列进回收范围进行二次回收。如果这次回收没有足够的内存,会抛出内存溢出异常

特点

当垃圾回收后,此时内存仍不够,软引用关联的对象会进行垃圾回收(内存不够才回收)

3.弱引用-发现就回收

介绍

弱引用是一些还有用但非必需的对象,生存到下一次垃圾回收为止。在系统进行垃圾回收时,发现弱引用,不管系统堆空间是否充足,都会回收软引用关联的对象。

特点

当发生垃圾回收时,弱引用关联的对象都会被回收。(内存不管够不够都回收)

4.虚引用-对象回收跟踪

介绍

当虚引用对象创建时会关联一个引用队列。虚引用在创建时必须提供引用队列作为参数。当垃圾回收准备回收一个对象时,如果发现他是虚引用,在垃圾回收后把这个虚引用加入引用队列,通知应用程序对象的回收情况。

5.终结器引用-引用队列配合

介绍

用于实现对象的finalize()方法。当终结器对象创建时会关联一个引用队列。当准备回收一个对象时,发现是终结器引用,会把终结器引用对象放入引用队列(此时对象没回收)。由Finalizer线程调用该对象的finalize()方法,第二次垃圾回收就会回收此对象。

2.垃圾回收算法

2.1标记清除

什么时候垃圾回收

扫描整个堆对象的过程中,如果发现对象被GC Root引用了,需要保留。如果这个对象没有被GC Root引用,就要进行垃圾回收。

标记清除算法的两个阶段

①把没有引用的对象标记为垃圾。

②把垃圾对象占用的空间释放,清除

③释放不是空间清0,而是把起始地址记录下来,然后将来把创建的新对象存储这个位置

优点

垃圾回收速度快

缺点

产生内存碎片

2.2标记整理

标记整理两个阶段

①把没有引用的对象标记为垃圾

②把可用的对象向前移动,让内存更加紧凑。连续的空间变多。

优点

没有内存碎片

缺点

对象整理过程中需要移动,垃圾回收效率低。

2.3复制

复制两个阶段

①把没有引用的对象标记为垃圾

②把活着的内存分为两块from区和to区。把from区存活的对象复制到to区。然后清空from区,然后交换from和to的位置

优点

没有内存碎片

缺点

占用双倍内存空间

3.分代垃圾回收

介绍

垃圾回收时,JVM结合3种算法协程工作。通过分代的垃圾回收机制,把堆内存划分为2块新生代和老年代,新生代(对象用完丢弃)划分为3个区域:伊甸园,幸存区From,幸存区To。

老年代(对象长时间使用) 不同的区域,算法不同。

 

工作机制

①创建新的对象占用伊甸园的内存空间,当伊甸园内存满时,触发垃圾回收Minor GC。沿着GC Roots引用链去找,如果对象没有被引用,就进行垃圾标记。然后采用复制的算法把伊甸园存活的对象复制到幸存区To中,并且对象寿命加1。然后交换from和to的位置。

 ②当伊甸园内存空间再次溢出时,触发第二次垃圾回收Minor GC。沿着GC Roots根引用链进行扫描伊甸园幸存区。把存活的对象复制到幸存区To中,并且对象寿命加1。然后交换from和to的位置。

 ③幸存区的对象寿命超过了阈值15,对象利用率高。晋升到老年代。(对象长时间使用

 ④当新生代老年代内存要溢出时,触发Full GC垃圾回收。

总结

①对象首先分配在伊甸园区域

②新生代空间不足时,触发Minor gc。伊甸园和from存活的对象,使用复制算法copy到to中。存活的对象年龄加1.交换from和to。

③minor gc会引发stop the world暂停其他用户的线程。垃圾回收结束,用户恢复运行。

④当对象寿命超过阈值时,会晋升到老年代,最大寿命是15

⑤老年代空间不足,触发Minor gc内存仍不足,那么full gc.

相关JVM参数

4.垃圾回收器

4.1串行垃圾回收器

介绍

①单线程垃圾回收器

②堆内存较小,适合个人电脑

③开启串行垃圾回收器 -XX:+UseSerialGC = Serial + SerialOld

Serial工作新生代,复制算法

SerialOld 工作在老年代,标记整理算法

工作流程

当堆内存要溢出时,触发垃圾回收。让其他线程在安全点停止下来,等待垃圾回收线程的结束。

 

4.2吞吐量优先:并行

介绍

①多线程

②堆内存较大,多核cpu支持

③让单位时间内,STW时间最短

工作流程

多核CPU中,有4个线程运行。当堆内存要溢出时,触发了垃圾回收。用户线程在安全点停止。此时的垃圾回收器会开启多个线程(跟CPU核数相关)进行垃圾回收。然后恢复其他线程的运行。

相关参数

-XX:+UseParallelGC ~ -XX:+UseParallelOldGC  开启吞吐量优先垃圾回收器

-XX:+UseAdaptiveSizePolicy  自适应大小策略,新生代

-XX:GCTimeRatio=ratio  调整吞吐量

-XX:MaxGCPauseMillis=ms 最大暂停毫秒数

-XX:ParallelGCThreads=n 运行时线程数

4.3响应时间优先

介绍

①多线程

②堆内存交大,多核cpu支持

③尽可能让单次STW时间变短

相关参数

-XX:+UseConcMarkSweepGC~-XX:+UseParNewGC~SerialOld 开启响应时间优先回收器

-XX:ParallelGCThreads=n~-XX:ConcGCThreads=threads 线程数

-XX:CMSInitiatingOccupancyFraction=percent 何时进行垃圾回收

-XX:+CMSScavengeBeforeRemark 新生代垃圾回收

工作流程

老年代发生内存泄漏,其他线程到达安全点暂停下来,垃圾回收器执行初始标记,用户线程恢复运行。垃圾回收线程进行并发标记,然后进行重新标记工作。垃圾回收线程进行并发清理。

5.G1垃圾回收器

简介

Garbage First

JDK 9默认

适用场景

①同时注重吞吐量和低延迟,默认暂停目标是200ms

②超大堆内存,会将堆划分多个大小相等的Region

③整体上是标记+整理算法,两个区域之间是复制算法。

相关JVM参数

-XX:+UseG1GC 开启G1垃圾回收

-XX:G1HeapRegisonSize=size 设置划分区域的大小

-XX:MaxGCPauseMills=time JVM最大暂停时间的目标值

5.1 G1垃圾回收阶段

1.Young Collection 新生代垃圾收集

①、G1会把堆内存划分成多个相等的区域。每个区域独立作为伊甸园,幸存区,老年代

②、新创建的对象会存储在伊甸园,当伊甸园内存满时会触发新生代垃圾回收机制,会STW。

③、伊甸园存活的对象使用copy算法到幸存区。

④、当幸存区的内存溢出时,触发新生代垃圾回收。幸存区对象存活年龄超过一定时间会晋升到老年代

2. Young Collection+Concurrent Mark新生代垃圾收集+并发标记

①在Young GC时进行GC Root的初始标记

②老年代占用堆空间比例达到阈值时,进行并发标记(不会STW)

-XX:InitiatingHeapOccupancyPercent=percent(默认45%)

3.Mixed Collection混合收集

介绍

会对E、S、O进行全面垃圾回收

①最终标记会STW

②拷贝存活会STW

-XX:MaxGCPauseMillis=ms

E:伊甸园区的存活对象通过复制算法到幸存区中

S:幸存区存活的对象复制到另一个幸存区,符合晋升条件的到老年区

O:老年代区把存活对象复制到另一个老年代区

优先收集垃圾最多的区,目的是达到暂停时间段的目标

5.2 Full GC     

1.SerialGC

①新生代内存不足发生的垃圾收集—minor gc

②老年代内存不足发生的垃圾收集—full gc

2.ParallelGC

①新生代内存不足发生的垃圾收集—minor gc

②老年代内存不足发生的垃圾收集—full gc

3.CMS

①新生代内存不足发生的垃圾收集—minor gc

②老年代内存不足,并发失败后才会full gc。

4.G1

①新生代内存不足发生的垃圾收集—minor gc

②老年代内存不足,老年代内存跟堆内存占比达到45%,触发并发标记和混合收集阶段。回收速度>垃圾产生速度,并发垃圾收集阶段。回收速度<垃圾产生速度,此时是full gc

5.3Young Collection跨代引用

1.新生代回收的跨代引用(老年代引用新生代)

①根对象有部分是来自老年代,老年代存活对象比较多,遍历效率低。所以采用CardTable把老年代区域进行细分成一个个的card。每个card是512k。如果老年代的对象引用了新生代的对象,就会把这个card标记为脏卡。只关注脏卡,减少搜索范围。

 ②脏卡引用了新生代的对象。新生代通过Remembered Set知道对应的脏卡。通过脏卡区域遍历GC Roots

5.4 Remark-重新标记

并发标记阶段的对象处理状态

 

黑色已经处理完成,存活的对象。灰色是处理当中的。白色是尚未处理的垃圾。

在并发标记阶段可能出现B对C引用,接着断开后C成为垃圾,然后A对C引用。此时C被判成垃圾了。

这个时候需要用到remark

Remark:对对象进行进一步检查,当对象引用发生改变时,会给引用提供一个写屏障(将C加入队列),接着进入重新标记阶段,对队列对象进行检查,有强引用的不标记为垃圾。

5.5 JDK8 u20字符串去重

指令

-XX:+UseStringDeduplication

规则

①将所有新分配的字符串放入一个队列

②当新生代回收时,G1并发检查是否有字符串重复

③如果值一样,让他们引用同一个char[]

优缺点

优点:节约大量内存

缺点:多占用CPU时间,新时代回收时间略微增加

跟String.intern()不一样

①String.intern()关注的是字符串对象

②字符串去重关注的是char[]

③JVM内部使用不同的字符串表

5.6 JDK8 u40并发标记类卸载

所有对象都经过并发标记后,知道哪些类不再使用。当一个类加载器所有类不再使用,则卸载它所加载的所有类

-xx:+ClassUnloadingWithConcurrentMark默认启用

5.7 JDK8 u60 回收巨型对象

①一个对象大于region的一半时,成为巨型对象。

②G1不会对巨型对象进行拷贝

③回收时优先考虑

④G1会跟踪老年代所有incoming引用。这样老年代incoming引用为0的巨型对象在新生代垃圾回收处理掉。

5.8 JDK9 并发标记起始时间的调整

①并发标记必须在堆空间占满前完成,否则退化为FullGC

②JDK 9之前需要使用 -XX:InitiatingHeapOccupancyPercent

③JDK 9可以调整:

-XX:InitiatingHeapOccupancyPercent 用来设置初始值

进行数据采样并动态调整

总会添加一个安全的空挡空间

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

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

相关文章

C++中使用R“()“标记符书写多行字符串

在C#中使用表示的字符串能够跨越数行。用于在C#中写JS或SQL代码比较方便。 string sqlInsert "INSERT INTO tb_param(protocol, slave, number, ptype, pid, name, format) VALUES(2, 24, 0, 1, 1, a04005, .3);INSERT INTO tb_param(protocol, slave, number, ptype, …

stm32---外部中断

一、EXTI STM32F10x外部中断/事件控制器&#xff08;EXTI&#xff09;包含多达20个用于产生事件/中断请求的边沿检测器。EXTI的每根输入线都可单独进行配置&#xff0c;以选择类型&#xff08;中断或事件&#xff09;和相应的触发事件&#xff08;上升沿触发、下降沿触发…

HashMap初始化大小

1.参考阿里巴巴开发规范 2.写了个工具类 供大家参考 import java.util.HashMap;/*** 阿里巴巴开发规范* 【推荐】 集合初始化时&#xff0c; 指定集合初始值大小。* 说明&#xff1a; HashMap 使用 HashMap(int initialCapacity) 初始化&#xff0c;如果暂时无法确定集合大小…

计算机二级公共基础知识-2023

计算机基础知识&#xff1a; 计算机的发展&#xff1a; 第一台电子计算机eniac 埃尼阿克 1946 第一台存储程序计算机 edvac 艾迪瓦克 根据电子元器件的发展分类 1.电子管 2.晶体管 3.集成电路 4.超大规模继承电路 按照电脑的用途可以分为 专用计算机 专门用于处理…

OpenCV学习笔记(6)_由例程学习高斯图像金字塔和拉普拉斯金字塔

1 图像金字塔 图像金字塔是图像多尺度表达的一种。 尺度&#xff0c;顾名思义&#xff0c;可以理解为图像的尺寸和分辨率。处理图像时&#xff0c;经常对源图像的尺寸进行缩放变换&#xff0c;进而变换为适合我们后续处理的大小的目标图像。这个对尺寸进行放大缩小的变换过程…

【C++从0到王者】第二十九站:二叉搜索树常见题

文章目录 一、根据二叉树创建字符串二、二叉树的最近公共祖先1.解法一&#xff1a;递归2.解法二&#xff1a;借助栈来寻找路径 三、二叉搜索树与双向链表四、前序与中序构建二叉树五、中序与后序构建二叉树 一、根据二叉树创建字符串 题目链接&#xff1a;力扣第606题&#xff…

Trinitycore学习之在Linux环境上搭建服务器并测试运行

1&#xff1a;准备环境&#xff0c;这里用ubuntu 22.04进行测试&#xff0c;安装环境后为了方便&#xff0c;换源。 注意&#xff1a;这里用的虚拟机&#xff0c;在虚拟机上生成地图信息&#xff0c;地图信息占用内存比较大&#xff0c;我暂时设置磁盘50G进行测试&#xff0c;…

Git学习记录

Contest 一、工作区域二、操作命令2.1 创建仓库2.2 查看仓库状态2.3 从工作区向暂存区添加文件2.3.1 只添加一个文件2.3.2 添加全部文件 2.4 从暂存区向仓库区添加文件2.5 查询日志2.5.1 从当前版本开始查询2.5.2 查看所有日志 2.6 回滚2.6.1 从仓库回滚到工作区2.6.2 取消工作…

c++的this指针

目录 this指针的工作原理 this指针的应用 const修饰的成员函数 this指针的工作原理 在c中同一个类的不同对象&#xff0c;在内存中有不同的储存空间&#xff0c;但是成员函数在内存中只保存了一份&#xff0c;在调用函数处理成员数据时&#xff0c;this指针能保证该成员函数…

2023大数据面试总结

文章目录 Flink&#xff08;SQL相关后面专题补充&#xff09;1. 把状态后端从FileSystem改为RocksDB后&#xff0c;Flink任务状态存储会发生哪些变化&#xff1f;2. Flink SQL API State TTL 的过期机制是 onCreateAndUpdate 还是 onReadAndWrite&#xff1f;3. watermark 到底…

《Graph of Thoughts: Solving Elaborate Problems with Large Language Models》中文翻译

《Graph of Thoughts: Solving Elaborate Problems with Large Language Models》- 思维图&#xff1a;用大型语言模型解决复杂的问题 论文信息摘要1. 介绍2. 背景及符号2.1 语言模型和情境学习 3. GoT 框架3.1 推理过程3.2 思想转变3.3 评分和排名思路 4. 系统架构及扩展性4.1…

驱动开发--自动创建节点udev机制的实现过程分析

一&#xff0c;创建设备文件的机制 1&#xff0c;mknod&#xff1a;手动创建设备节点 2&#xff0c;devfs&#xff1a;创建设备节点的逻辑在内核空间&#xff0c;2.5版本后淘汰 3&#xff0c;udev&#xff1a;自动创建设备节点的机制&#xff0c;逻辑在用户空间&#xff0c;…