代码编织梦想


GC 如何判断对象可以被回收
JVM 通过可达性分析算法来判断对象是否存活,从 GC Roots 开始,根据引用关系向下搜索,所经过的路径形成
引用链 Reference Chain, 不在引用链上的对象,到 GC Roots 不可达,视为可回收对象
----------------------------------------------------
什么是 GC Roots?
GC Roots 是一组活跃的引用
主要包括
1. 静态变量
方法区中类静态属性引用的对象
2. 常量
方法区中常量引用的对象
3. 局部变量
虚拟机栈(栈帧中的本地变量表)中引用的对象
4. 本地方法栈中 JNI (native 方法) 中引用的对象
5. java 虚拟机内部的引用,如基本数据类型对应的 class 对象,系统类加载器,常驻异常对象
6. 同步锁 synchronized 持有的对象
----------------------------------------------------
强引用 strongly reference
Object obj = new Object();
只要引用关系还在,垃圾收集器无法回收

软引用 soft reference
系统抛出 OOM 之前,进行二次回收
通过 SoftReference 类实现

弱引用 Weak reference
下一次 GC 回收
通过 WeakReference 类实现, 可用于缓存中的对象

虚引用 phantom reference
又称 幽灵引用 或 幻影引用
无法通过虚引用拿到引用的对象
虚引用被回收时,会收到一个系统通知
通过 PhantomReference 类实现
----------------------------------------------------
方法区类对象的回收规则
1. 该类的所有实例都已经被回收
2. 加载该类的 ClassLoader 已经被回收了
3. 该类的 class 对象没有在代码中被引用
----------------------------------------------------
你知道哪些 GC 类型?
新生代收集 Minor GC / Young GC
针对新生代的垃圾收集

老年代收集 Old GC
针对老年代的垃圾收集

整堆收集 Full GC
对整个 java 堆和方法区的垃圾收集

运行时常量池 垃圾回收
在常量池中存在字符串 "abc",如果当前没有任何 String 对象引用该字符串常量,常量 "abc" 就是废弃常量,垃圾回收的时候且有必要的话,"abc" 就会被系统清理出常量池

常量池中的类,接口,方法,字段的符号引用与此类似
----------------------------------------------------
标记 - 清除算法 
Mark - Sweep
首先标记所有存活的对象,然后统一回收所有未标记的对象, 如果需要回收的对象很多,效率就会降低, 会产生大量不连续的内存碎片,以后需要分配大对象时, 没有足够大的连续内存, 可能会提前触发一次 GC
----------------------------------------------------
标记 - 复制算法
Mark - Copy
为了解决内存碎片问题, 将可用内存分为大小相等的两块, 每次只使用其中一块, 当使用的这块空间不够用了, 就将存活对象复制到另一块, 再把已使用过的内存空间一次清理掉, 主要用于新生代
实现简单, 运行高效, 解决了内存碎片问题, 代价是可用内存会变小, 要留一部分空间来倒腾存活对象

HotSpot 虚拟机把新生代划分为一块较大的 Eden 和两块较小的 Survivor, 每次分配内存只使用 Eden 和其中一块 Survivor, 垃圾收集时将 Eden 和 Survivor 中仍然存活的对象一次性复制到另一块 Survivor 上, 然后直接清理掉 Eden 和已用过的那块 Survivor
 
HotSpot 虚拟机默认 Eden 和 Survivor 的大小比例是 8:1, 即新生代可用内存空间为整个新生代容量的 90%

如果另一块 Survivor 不够空间存放上一次新生代收集下来的存活对象, 这些对象就通过分配担保机制直接进入老年代
----------------------------------------------------
标记 - 整理算法 
Mark - Compact
一般用于老年代,首先标记所有存活的对象,然后把所有存活对象都移向内存空间一端, 最后清理掉边界以外的内存
----------------------------------------------------
OopMap - ordinary object pointer Map
安全点 - safe point
HotSpot 虚拟机在指令流的特定位置生成 OopMap, 记录栈中引用类型数据的位置, 
垃圾收集之前, 必须让用户线程在指令流里 OopMap 的位置停下来, 这些位置就叫 安全点

虚拟机需要暂停用户线程, 就设置一个标志位, 用户线程会轮询这个标志位, 看是否需要中断挂起

安全区域 Safe Region
某一段代码片段中,引用关系不会发生变化,用户线程在这段代码片段里时, 并不妨碍虚拟机垃圾回收,所以叫安全区域

用户线程执行到安全区域里的代码时, 会标识自己进入安全区域, 
当用户线程要离开安全区域时, 会检查虚拟机是否还处于需要暂停用户线程的阶段, 看情况决定是否等待

记忆集
是一种用于记录从非收集区域指向收集区域的指针集合的抽象数据结构

卡表
卡表是一个字节数组, 每一个元素都对应着一个特定大小的内存块, 叫卡页, 卡表用来记录哪些卡页里的对象含有跨代引用, 垃圾收集时, 就把它们加入 GC Roots 中一并扫描

写屏障
hotSpot 虚拟机通过写屏障来维护卡表状态, 写屏障可以看作是在虚拟机层面对 引用类型字段赋值 的 AOP 切面, 虚拟机会为所有赋值操作生成相应的指令, 更新卡表
----------------------------------------------------
三色标记算法
白色 未扫描,或已扫描不可达
黑色 已扫描,且安全存活
灰色 正在扫描

三色标记算法缺陷
并发标记阶段,有可能会产生多标或者漏标

多标
用户线程去掉了黑色到灰色的引用

漏标 - 需同时满足2个条件
1.用户线程去掉了灰色到白色的引用
原始快照
可以通过写屏障记录下来要删除的引用,等并发扫描结束之后,再将这些记录过的引用关系扫描一次,就好像按照删除前的对象图快照扫描

2.用户线程增加了黑色到白色的引用
增量更新
可以通过写屏障记录下来黑到白的引用,等并发扫描结束之后,再将这些记录过的引用关系扫描一次

hotSpot 虚拟机中, CMS 基于增量更新做并发标记, G1, Shenandoah 则是用原始快照来实现
----------------------------------------------------
并行 parallel
在谈垃圾收集器的时候,并行就是 有多条垃圾收集器线程协同工作,而用户线程处于等待状态

并发 concurrent
在谈垃圾收集器的时候,并发就是 垃圾收集器线程与用户线程同时工作
----------------------------------------------------
serial 收集器
新生代,标记复制算法,单线程收集器
客户端模式下默认的新生代收集器,适合小内存环境
----------------------------------------------------
serial old 收集器
老年代,标记整理算法,单线程收集器
可用于客户端模式下,也可用于服务器模式下 CMS 收集器收集垃圾报错时候的后备方案
----------------------------------------------------
parnew 收集器
新生代,标记复制算法,多线程并行收集,多 CPU 环境 Server 模式与 CMS 配合使用
jdk 7 之前服务端模式下的首选新生代收集器
----------------------------------------------------
parallel scavenge 收集器
标记复制算法,并行收集器
适合注重吞吐量,如没有太多交互的后台运算
----------------------------------------------------
parallel old 收集器
老年代,标记整理算法,并行收集器
适合注重吞吐量,如没有太多交互的后台运算
----------------------------------------------------
CMS 问题很多,jdk 1.8 和后面的版本都没有把它设置成默认的垃圾回收器
jdk 9 不推荐使用, jdk 14 remove 掉

jdk 1.8 里 CMS 有 83 个参数
java -XX:+PrintFlagsFinal|grep CMS

jdk 1.8 里 G1 有 24 个参数
java -XX:+PrintFlagsFinal|grep G1
----------------------------------------------------
CMS 收集器 - Concurrent mark sweep
老年代,标记清除算法,并发收集器
目标是获取最短垃圾回收停顿时间,适合关注服务响应时间的互联网应用

整个过程分为以下4个步骤
1.初始标记
只是标记一下 GC Roots 能直接关联的对象, 速度很快, 需要暂停用户线程

2.并发标记
从 GC Roots 直接关联的对象开始遍历整个对象图的过程, 和用户线程一起工作

3.重新标记
通过 增量更新 来处理并发标记阶段, 因用户线程继续运行而产生的漏标, 需要暂停用户线程

4.并发清除
清除 GC Roots 不可达对象, 和用户线程一起工作

由于耗时最长的 并发标记 和 并发清除 阶段, 垃圾收集线程和用户线程并发工作,  所以总体上来看 CMS 收集器的内存回收 和 用户线程 是一起并发执行

分代设计
90% 的对象朝生夕灭
----------------------------------------------------
内存分配回收策略
对象优先在 Eden 区分配
对象在新生代 Eden 区分配, 当 Eden 区不够空间分配时, 触发 Minor GC, Eden 区里的存活对象, 会进入 Survior 区, 如果 Survior 区放不下, 通过分配担保机制提前转移到老年代

大对象直接进入老年代
为了避免大对象在 Eden 区和两个 Survior 区之间来回复制, 产生大量的内存复制动作, 
Serial 和 ParNew 两款新生代收集器提供了一个参数配置, 大于该参数的对象直接在老年代分配
-XX: PretenureSizeThreshold

长期存活的对象将进入老年代
对象在 Eden 区诞生, 熬过一次 Minor GC 后仍然存活, 且能被 Survior 容纳的话, 该对象被转移至 Survior 区, 对象头里的 Age 变成 1, 以后在 Survior 区每熬过一次 Minor GC, 年龄就增加一岁, 当年龄达到阈值(默认15), 就晋升到老年代
-XX:MaxTenuringThreshold

动态对象年龄判定
当同年对象大小总和大于 survivor 空间一半,可以直接进入老年代 
----------------------------------------------------
Minor GC 还是 Full GC
在 Minor GC 之前, 虚拟机会判断, 老年代的连续可用空间是否大于 新生代对象的总大小, 
或者历次晋升的平均大小, 如果大于就 Minor GC, 否则就 Full GC

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_43820780/article/details/129631174

JVM 垃圾回收详解-爱代码爱编程

JVM 垃圾回收 1.概述 JVM 会自动帮程序员进行垃圾回收,并不需要程序员手动的进行垃圾回收(C++等语言需要自己手动回收垃圾),了解 JVM 的垃圾回收,可以帮程序员写出占用内存更小、更高效的程序。 1.1 什么是垃圾? 垃圾是指运行程序中没有任何指针指向的对象,这个对象就是需要被回收的垃圾。 1.2 什么区域需要进行垃圾回收 JVM 的

JVM垃圾回收器-爱代码爱编程

1 垃圾回收器的位置 2 垃圾回收器的基本概念   什么是垃圾回收器:JVM 为 Java 提供了垃圾回收机制,是一种偏自动的内存管理机制。简单来说,垃圾回收器会自动追踪所有正在使用的对象,并将其余未被使用的对象标记为垃圾,JVM会自动进行垃圾回收,释放内存。   哪些内存需要回收:不可能再被任何途径所使用的对象,Java中通过可达性分析法来检测

JVM垃圾回收算法-爱代码爱编程

一、垃圾回收算法 1、标记复制算法 会把内存分为相同的2个部分,每次回收,会把存活的对象移动到另一边,回收当前使用的空间。分配的内存被分成2份,实际使用空间变成正常的一半。但是不会出现垃圾碎片。 2、标记清除算法 标记存活的对象,把未标记的回收。回收后内存不是连续的,会产生大量的不连续的碎片,标记对象的时候效率低。 3、标记整理(压缩)算法 会

JVM垃圾回收机制-爱代码爱编程

文章目录 JVM垃圾回收机制一、垃圾回收原理二、对象被标记为垃圾方法1. 引用计数器2. 可达性分析三、垃圾回收算法1. 标记-清除算法2. 复制算法3. 标记-整理算法4. 分代回收算法 JVM垃圾回收机制 一、垃圾回收原理 GC (Garbage Collection:即垃圾回收)的基本原理:将内存中不再被使用的对象进行回收,GC中用于

jvm 垃圾回收(常见算法介绍)_老板是nc的博客-爱代码爱编程

1. 什么是垃圾回收? 程序的运行必然申请内存资源,如果无效的对象不清理一直占用资源,那么肯定会导致内存溢出,所以内存资源的管理就很重要了 2. 垃圾回收的常见算法 2.1、 引用计数法 2.1.1 原理 假设有一个对象a,任何对对象A的引用,引用计数器都会加1,当引用失败时,对象A的引用计数器就-1,如果对象计数器的值为0,表示对象没有引用可以

简述jvm垃圾回收机制_燕麦牛奶小米粥的博客-爱代码爱编程

目录 一、四种垃圾回收方法 (1)标记清除 (2)标记整理 (3)复制算法 (4)分代收集 二、垃圾回收机制 jvm内存结构 垃圾回收有两种类型:Minor GC 和 Full GC 1.Minor GC 2.Full GC 一、四种垃圾回收方法 (1)标记清除 标记阶段 清除阶段 缺点: 可能产生

jvm垃圾回收机制查看及说明_冷冷清清中的风风火火的博客-爱代码爱编程

此文查看操作,是在windows环境下进行的 1、查看java版本 java -version 2、如果不知道java安装路径,想查看安装路径的话,可执行 java -verbose 执行上述命令后,会在最后打印出如下信息: 3、查看jvm使用的垃圾收集器 java -XX:+PrintCommandLineFlags -version

jvm垃圾回收器cms详解_bjzw的博客-爱代码爱编程

关于serial,parnew,parallel等回收器的介绍可以参考上一篇jvm垃圾回收算法以及垃圾回收器,如何选择_bjzw的博客-CSDN博客 下面具体介绍一下cms,jdk8之后就已经废弃了cms垃圾回收器,为什么要还要详解cms呢         首先,cms的回收思想需要我们了解         其次,G1回收器也复用了cms的一部分思想

jvm垃圾回收机制_橙嚼嚼的博客-爱代码爱编程

JVM垃圾回收机制 垃圾回收机制是JVM的重要特点,简单介绍一下JVM垃圾回收 什么算垃圾 JVM垃圾回收时要标记出“垃圾”并清理,那什么算垃圾呢? 垃圾可以理解为内存中没用了的对象,那哪些是没用的对象呢? 有两个

linux小黑板(12):linux系统下的线程-爱代码爱编程

"泥土里的蚂蚁哪儿能搞懂,天边的海鸥?" 我们翻开任意一本讲操作系统的书籍,对于进程的描述,一个最经典的定义是:一个"执行中的实例"。那么什么是线程呢?一本书给的定义是:"线程是进程中的一个实体,是被系统独立调用和运行的基本单位。",另一本书给的定义是:"运行在进程上下文中的逻辑流。"从书本上给的定义来看

jvm监控搭建-爱代码爱编程

文章目录 JVM监控搭建整体架构JolokiaTelegrafInfluxdbGrafana JVM监控搭建 整体架构 JVM 的各种内存信息,会通过 JMX 接口进行暴露。 Jolokia

jvm垃圾回收-爱代码爱编程

文章目录 垃圾回收原理 对象被标记为垃圾方法 引用计数器 可达性分析 垃圾回收算法

【黑马jvm(2)】垃圾回收_-爱代码爱编程

JVM垃圾回收 如何判断对象可以回收引用计数法可达性分析算法四种引用 垃圾回收算法标记-清除标记-整理标记-复制分代垃圾回收相关VM参数 垃圾回收器串行吞吐量优先响应时间优先G1垃圾回收阶段Youn