IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> Java中对象何时需要回收?常见的 GC 回收算法有哪些? -> 正文阅读

[数据结构与算法]Java中对象何时需要回收?常见的 GC 回收算法有哪些?


hello
今天我们就从头到尾完整地聊一聊 Java 的垃圾回收。

1、什么是垃圾回收

垃圾回收(Garbage Collection),释放垃圾占用的空间,防止内存泄露,对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收。

2、如何定义垃圾

既然要做垃圾回收,那么就得知道垃圾的定义是什么,哪些内存需要回收。

2.1 引用计数算法

通过在对象头部分配一个空间,来保存该对象被引用的次数。对象被其他对象引用,则它的计数加1,删除该对象的引用,计数减1,当该对象计数为0时,会被回收。

String m = new String("方糖算法");

创建一个字符串m,这时候"方糖算法"字符串被m引用了,"方糖算法"字符串计数加1。
引用计算算法
此时将m设置为null,则"方糖算法"的引用次数就变为0,意味着要被回收了。

m = null;

引用计数算法
引用计数算法将垃圾回收分摊到整个程序运行中,而不是在垃圾收集时,不属于严格意义上的"Stop-The-World"的垃圾收集机制。

JVM放弃了引用计数算法,这是为什么?我们看下面的例子。

public class ReferenceCountingGC {

    public Object instance;

    public ReferenceCountingGC(String name){}
}

public static void testGC(){

    ReferenceCountingGC a = new ReferenceCountingGC("objA");
    ReferenceCountingGC b = new ReferenceCountingGC("objB");

    a.instance = b;
    b.instance = a;

    a = null;
    b = null;
}
  1. 定义2个对象a,b
  2. 相互引用
  3. 声明引用置空
    引用计数缺点
    从图中,ab置空后,这两个对象已经不能被访问了,但是他们相互引用对方,导致他们两个的计数永远不为0,永远不会被回收。

2.2 可达性分析算法

通过引用链(GC Root)作为起点,向下搜索,搜索过的路径被称为(Reference Chain)。当一个对象不能被引用链搜索到,说明该对象不可用,被回收。
可达性算法
通过可达性算法,可以解决引用计数算法无法解决的循环依赖问题,只要不能被GC Root搜索到,就会被回收。

那么哪些属于GC Root?往下看鸭!

2.3 Java内存区域

在Java中,GC Root 对象包括四种:

  • 虚拟机栈中的引用对象
  • 方法区静态属性引用的对象
  • 方法区常量引用的对象
  • 本地方法栈JNI引用的对象
    内存区域

虚拟机栈中的引用对象
此时的 s,即为GC Root。 当s置空时,localParameter对象也断掉与GC Root 的引用链,将被回收。

public class StackLocalParameter {
    public StackLocalParameter(String name){}
}

public static void testGC(){
    StackLocalParameter s = new StackLocalParameter("localParameter");
    s = null;
}

方法区静态属性引用的对象
s 为 GC Root,s 置空后,s 指向的 properties对象被回收。
m 为类静态属性,也属于GC Root,parameter对象依旧与 GC Root 连接着,所以不会被回收。

public class MethodAreaStaicProperties {
    public static MethodAreaStaicProperties m;
    public MethodAreaStaicProperties(String name){}
}

public static void testGC(){
    MethodAreaStaicProperties s = new MethodAreaStaicProperties("properties");
    s.m = new MethodAreaStaicProperties("parameter");
    s = null;
}

方法区常量引用的对象
m 为常量引用,是GC Root,s 置空后,final对象也会被回收。

public class MethodAreaStaicProperties {
    public static final MethodAreaStaicProperties m = MethodAreaStaicProperties("final");
    public MethodAreaStaicProperties(String name){}
}

public static void testGC(){
    MethodAreaStaicProperties s = new MethodAreaStaicProperties("staticProperties");
    s = null;
}

本地方法栈中引用的对象
任何 Native 接口都会使用某种本地方法栈,实现的本地方法是使用 C 连接模型的话,那么它的本地方法栈就是 C 栈。
当线程调用 Java 方法时,虚拟机会创建一个新的栈帧并压入 Java 栈,然而当它调用的是本地方法时,虚拟机会保持 Java 栈不变,虚拟机只是简单地动态连接并直接调用指定的本地方法。

3、怎么回收垃圾

在确定哪些垃圾可以回收后,我们来讨论一下如何高效的回收垃圾呢?

Java虚拟机没有规定实现垃圾收集器,所以各个厂商的虚拟机可以采用不同的方法实现垃圾收集器。

3.1 标记清除算法

标记清除
标记清除算法(Mark - Sweep),分为 2 部分,①先把内存中可回收的标记出来再把这些清理掉 ,清理完的区域变成未使用,等待下次使用。

但是存在一个很大的问题,那就是内存碎片

假设图中 中等方块是 2M,小的是 1M,大的是 4M。等回收完,内存就会被切成很多段。而开辟内存需要的是连续区域,需要一个 2M 的内存,用 2个 1M 是没法用的。这样就导致,其实内存还挺多,但是分散了无法使用。

3.2 复制算法

复制算法
复制算法(Copying),是在MS算法上演变而来,解决了内存碎片问题。它将内存按容量平分成两块,每次使用其中的一块。当一块用完了,将其存活的对象复制到另一块上,再把这一块内存清理掉。保证了内存连续可用,不会产生内存碎片,逻辑清晰,运行高效。

但是明显暴露了一个问题,合着我 300 平的别墅,只能当 150 平的小三房来使?代价太高了

3.3 标记整理算法

标记整理
标记整理算法(Mark - Compact)标记过程与MS算法一样,但后续不是直接回收对象,而是让存活的对象向一端移动,再清理端边界以外的内存

不仅解决了内存碎片,也规避了只能使用一半的内存。但是问题又来了,它对内存变动更频繁,需要整理所有存活对象的引用地址,在效率上比MS算法差很多。

3.4 分代收集算法

分代收集算法(Generational Collection),融合上面 3 种思想。 根据对象存活周期的不同划分为几块,一般分为新生代老年代,根据年代的特点采用适当的收集算法。

新生代:每次回收发现有大量对象死去,少量存活,则使用复制算法,付出少量存活对象复制的成本完成回收。
老年代:存活率高,没有额外空间分配,则使用MS,MC算法来回收。

问题又来了,内存区域被分为哪几块,每一块又用什么算法合适?

4、内存模型与回收策略

内存模型
Java 堆(Heap)是 JVM 管理的内存最大的一块,堆又是垃圾收集器管理的主要区域,我们来分析一下堆的结构。

堆主要分为 2 个区域,年轻代和老年代。年轻代分为 EdenSurvivor,其中 Survivor 又分为 FromTo ,老年代分为 Old

Eden
研究表名,98%对象是朝生夕死,所以大部分情况,对象会在新生代的 Eden 区分配,当 Eden 内存不足时,虚拟机发起一次 Minor GC, Minor GC 比 Major GC 更频繁,回收更快。

通过 Minor GC 后,Eden会被清空,绝大部分对象被回收,而那些存活对象会进入 Survivor 的 From 区(From 区不够,则进入 Old 区)。

Survivor
Survivor 相当于 Eden 区和 Old 区的一个缓冲区。通过 Minor GC 后,会将 Eden 区和 From 区的存活对象放到 To 区(To 区不够,则进入 Old 区)。

为啥需要缓冲区?

不就是新生代到老年代吗,直接 Eden 到 Old 不就好了?非要这么复杂。
如果没有 Survivor 区,Eden 区每进行一次 Minor GC,存活的对象就会被送到 Old 区,老年代很快被填满。而且很多对象虽然一次 Minor GC 后没有死,可能一会后就死了,直接把它送入老年代,明显不合适。

总结:Survivor 存在的意义就是减少被送到老年代的对象,减少 Major GC 的发送。Survivor 的预筛保证,只有经历16次 Minor GC 还能在新生代中存活的对象,才会被送到老年代。

为啥需要两个缓冲区?
两个 Survivor 最大的好处是解决内存碎片化

如果 Survivor 有1个区域,Minor GC 执行后,Eden 区被清除,存活对象放入 Survivor 区,而之前 Survivor 区的对象可能也有一部分要清除。此时只能使用MS算法,那就会产生内存碎片,尤其是在新生代这种经常死亡的区域,产生严重碎片化。

如果 Survivor 有2个区域,每次 Minor GC,会将之前 Eden 区和 From 区中的存活对象复制到 To 区域。第二次 Minor GC 时,From 与 To 职责切换,这时候会将 Eden 区和 To 区中的存活对象再复制到 From 区域,以此反复。(有点复制算法的感觉)

这种机制最大的好处就是,永远有一个 Survivor 区是空的,另一个 区是无碎片的。那为啥不分更多的 Survivor 区呢?分的越多,每个区就越小,两块是经过权衡的最佳方案。

Old
老年代占据着 2/3 的堆内存,只有 Major GC 才会清理,每次 GC 都会触发 “Stop-The-World”。内存越大 STW时间越长,所以内存不是越大越好。老年代对象存活时间较长,采用MC算法

除了上面说的,无法安置的对象会直接送入老年代,以下情况也可以。

  • 大对象
    大对象是需要大量连续空间的对象,不管是不是"朝生夕死",都会直接进入老年代。避免在 Eden 和 Survivor 中来回复制。
  • 长期存活对象
    虚拟机给每个对象定义了对象年龄计数器。对象在 Survivor 区每经历一次 Minor GC ,年龄加1,当年龄为15岁,直接进入老年代。这里的15可以设置。
  • 动态对象年龄
    虚拟机不关注年龄必须到15岁才可以进入老年代,如果Survivor 区相同年龄的所有对象大小超过 Survivor 空间一半,则年龄大于相同年龄的对象就进入老年代,无需成年。

5、微信关注『方糖算法』

各类面试资料、内推资源,关注微信公众号获取哦。

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-10-16 19:53:24  更:2021-10-16 19:53:43 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 6:38:22-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码