概述
垃圾收集器需要判断三件事情:
- 哪些内存需要回收;
- 什么时候回收;
- 如何回收。
各区域概述
程序计数器,虚拟机栈,本地方法栈三个曲月随线程而生,随线程而灭,其中内存的大小基本上在类结构确认时就已知,内存分配和回收具有确定性,不需要过多考虑
Java堆和方法去具有很显著的不确定性
判断对象是否存活
- 1.应用计数法:在对象中添加一个引用器,每当一个地方引用他时,计数器加一,引用失效时,计数器减一。
占用了一定的内存空间,但原理简单,判断效率高,python语言使用方式
但这种方法需要考虑很多例外情况,例如对象的相互引用 - 2.可达性分析:通过一系列称为GC Roots的根对象作为起始点集,从这些结点出发,根据引用关系向下搜索,判断对象是否可达
GC Roots对象包括:在虚拟机栈中引用的对象;在方法区中类静态属性引用的对象;在方法区中常量引用的对象;在本地方法栈中JNI引用的对象
引 用 定 义 { 强 引 用 : 在 程 序 代 码 中 普 遍 存 在 的 引 用 赋 值 , 只 要 存 在 永 不 回 收 软 引 用 : 还 有 用 , 但 非 必 须 , 内 存 溢 出 时 , 列 入 二 次 回 收 列 表 弱 引 用 : 垃 圾 回 收 发 生 时 , 必 被 回 收 虚 引 用 : 目 的 是 在 对 象 被 回 收 是 可 以 接 收 到 通 知 引用定义\begin{cases} 强引用:在程序代码中普遍存在的引用赋值,只要存在永不回收\\ 软引用:还有用,但非必须,内存溢出时,列入二次回收列表 \\ 弱引用:垃圾回收发生时,必被回收\\ 虚引用:目的是在对象被回收是可以接收到通知\end{cases} 引用定义⎩⎪⎪⎪⎨⎪⎪⎪⎧强引用:在程序代码中普遍存在的引用赋值,只要存在永不回收软引用:还有用,但非必须,内存溢出时,列入二次回收列表弱引用:垃圾回收发生时,必被回收虚引用:目的是在对象被回收是可以接收到通知
回收一个对象对象要经过两个阶段: - 可达性分析,不可达标记
- 筛选对象是否有必要进行finalize()方法
方法区垃圾回收主要包括废弃的常量和不再使用的类型.
垃圾回收算法–基础理论–分代收集理论
- 弱分代假说:绝大多数对象都是朝生夕灭的
- 强分代假说:熬过越多次垃圾收集过程的对象就越难以消亡
- 跨代引用假说:跨代引用相对于同代引用来说占极少数
收 集 区 域 { 部 分 收 集 { 新 生 代 收 集 : 目 标 只 有 新 生 代 老 年 代 收 集 : 目 标 只 有 老 年 代 混 合 收 集 : 目 标 时 整 个 新 生 代 和 部 分 老 年 代 整 堆 收 集 : 对 整 个 J a v a 堆 和 方 法 区 的 收 集 收集区域\begin{cases}部分收集 \begin{cases} 新生代收集:目标只有新生代\\ 老年代收集:目标只有老年代\\混合收集:目标时整个新生代和部分老年代\end{cases}\\ 整堆收集:对整个Java堆和方法区的收集 \end{cases} 收集区域⎩⎪⎪⎪⎨⎪⎪⎪⎧部分收集⎩⎪⎨⎪⎧新生代收集:目标只有新生代老年代收集:目标只有老年代混合收集:目标时整个新生代和部分老年代整堆收集:对整个Java堆和方法区的收集
标记–清除算法
先标记对象是否可回收,在同意进行回收
- 执行效率不高,需要对大量对象进行标记
- 内存空间碎片化
标记–复制算法
将内存空间按容量大小划分为大小相等的两块,每次只使用其中的一块,用完之后将存活的对象转移,在清理整个区域
- 实现简单,无内存空间碎片化
- 代价时内存空间减少一半
大多数Java虚拟机以此方法回收新生代,改进成将内存空间划分为一块较大的eden空间和两块较小的survival空间(8:1:1),依赖分配担保,直入老年区
标记–整理算法
将所有的存活对象向内存的一端移动,多用于老年区
- 移动存活对象负重较大,且需要暂停用户应用程序
- 平时多使用标记-清除算法,空间碎片化无法容忍后,使用标记-整理算法