目录
目录
引用计数算法
定义:
缺点 :
可达性分析算法
标记-清除算法
缺点
标记-整理算法
缺点
标记-复制算法
优缺点
分代回收
分代收集算法
分区收集算法
相关 VM 参数
四种引用
1. 强引用
2. 软引用(SoftReference)
3. 弱引用(WeakReference)
4. 虚引用(PhantomReference)
5. 终结器引用(FinalReference)

引用计数算法
定义:
在对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加一;当引用失效时,计数器值就减一;任何时刻计数器为零的对象就是不可能再被使用的
缺点 :
如果存在 循环引用 最终导致无法回收

是指
A对象里引用了B对象 ,而B对象也引用了A对象 导致 这2个对象各个计数器值 都为 1,最终导致无法回收对象
可达性分析算法
这个算法的基本思路就是通过 一系列称为“GC Roots”
的根对象作为起始节点集,从这些节点开始,根据引用关系向下搜索,搜索过程所走过的路径称为“
引用链
”
(
Reference Chain
),如果某个对象到
GC Roots
间没有任何引用链相连, 或者用图论的话来说就是从GC Roots
到这个对象不可达时,则证明此对象是不可能再被使用的

在
Java
技术体系里面,固定可作为
GC Roots
的对象包括以下几种:
- ·在虚拟机栈(栈帧中的本地变量表)中引用的对象,譬如各个线程被调用的方法堆栈中使用到的 参数、局部变量、临时变量等。
- ·在方法区中类静态属性引用的对象,譬如Java类的引用类型静态变量。
- ·在方法区中常量引用的对象,譬如字符串常量池(String Table)里的引用。
- ·在本地方法栈中JNI(即通常所说的Native方法)引用的对象。
- ·Java虚拟机内部的引用,如基本数据类型对应的Class对象,一些常驻的异常对象(比如NullPointExcepiton、OutOfMemoryError)等,还有系统类加载器。
- ·所有被同步锁(synchronized关键字)持有的对象。
- ·反映Java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等。
简单来说
可达性分析算法 首先确定根对象 即肯定不能被当成垃圾被回收的对象,在进行垃圾回收之前,会对堆内存中对象进行扫描,看看这些对象 被根对象是否直接或间接引用,如果是,则不能被垃圾回收 ,如果没有被根对象间接引用或者直接引用 ,将会被垃圾回收
比方 ,洗一串葡萄,洗完后,拎起葡萄根,如果连在跟上的葡萄果就是不能被回收的对象(因为有根对象来引用他们),和葡萄根断开的葡萄,就是可以被回收的垃圾对象 (因为没有根对象引用他们)
标记-清除算法
算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后,统一回收掉所有被标记的对象,也可以反过来,标记存活的对象,统一回 收所有未被标记的对象。标记过程就是对象是否属于垃圾的判定过程

缺点
第一个是执行效率不稳定
如果Java堆中包含大量对象,而且其中大部分是需要被回收的,这时必须进行大量标记和清除的动作,导致标记和清除两个过程的执行效率都随对象数量增长而降低;
第二个是内存空间的碎片化问题,
标记、清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致当以后在程序运行过程中需要分配较大对象时无法找 到足够的连续内存而不得不提前触发另一次垃圾收集动作。
标记-整理算法
其中的标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向内存空间一端移动,然后直接清理掉边界以外的内存

缺点
如果移动存活对象,尤其是在老年代这种每次回收都有大量对象存活区域,移动存活对象并更新 所有引用这些对象的地方将会是一种极为负重的操作,而且这种对象移动操作必须全程暂停用户应用 程序才能进行
但如果跟标记
-
清除算法那样完全不考虑移动和整理存活对象的话,弥散于堆中的存活对象导致的空间碎片化问题就只能依赖更为复杂的内存分配器和内存访问器来解决。譬如通过“
分区空闲分配链 表”
来解决内存分配问题(计算机硬盘存储大文件就不要求物理连续的磁盘空间,能够在碎片化的硬盘
上存储和访问就是通过硬盘分区表实现的)。内存的访问是用户程序最频繁的操作,甚至都没有之 一,假如在这个环节上增加了额外的负担,势必会直接影响应用程序的吞吐量。
HotSpot虚拟机里面关注吞吐量的Parallel Scavenge收集器是基于标记-整理算法的,而关注延迟的CMS收集器则是基于标记-清除算法的
总结 :速度慢
标记-复制算法
它将可用 内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着 的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。
HotSpot虚拟机具体做法是把新生代分为一块较大的Eden空间和两块较小的 Survivor(幸存者)空间,每次分配内存只使用Eden和其中一块Survivor。发生垃圾搜集时,将Eden和Survivor(from 区)中仍 然存活的对象一次性复制到另外一块Survivor空间(to 区)上,然后直接清理掉Eden和已用过的那块Survivor空间,同时因为
from区空了,所以变为to区,
之前的to区有对象了,所以为from区
如果另外一块 Survivor空间没有足够空间存放上一次新生代收集下来的存活对象,这些对象便将通过分配担保机制直接进入老年代,
HotSpot虚拟机默认Eden和Survivor的大小比例是8∶1
,也即每次新生代中可用内存空间为整个新生代容量的90%
(
Eden
的
80%
加上一个
Survivor
的
10%
),只有一个
Survivor
空间,即
10%
的新生代是会 被“
浪费
”
的
当然 也有一种情况 就是大对象问题 如果 某一个对象占用内存大于新生代内存 ,但是小于老年代内存大小,会将这个对象直接晋升到 老年代,同时不会触发GC

出现堆内存溢出,一个线程的堆内存溢出不会影响主进程的操作,同时这个线程抛出OOM异常后,它所占据的内存资源会不会被释放掉、
理由 : 主线程可能会使用这个线程里的某些参数



优缺点
好处:没有内存的碎片
坏处:浪费了内存空间 :多了一半空间永远是空to
分代回收

对象首先分配在伊甸园区域
新生代空间不足时,触发
minor gc
,伊甸园和
from
存活的对象使用
copy
复制到
to
中,存活的
对象年龄加
1
并且交换
from to
minor gc
会引发
stop the world
,暂停其它用户的线程,等垃圾回收结束,用户线程才恢复运行
当对象寿命超过阈值时,会晋升至老年代,最大寿命是
15
(
4bit
)
当老年代空间不足,会先尝试触发
minor gc
,如果之后空间仍不足,那么触发
full gc,暂停其它用户的线程的时间更长
分代收集算法
JVM根据对象存活周期的不同将内存划分为新生代、老年代和永久代,并根据各年代的特点分别采用不同的GC算法
分区收集算法
分区算法将整个堆空间划分为连续的大小不同的小区域,对每个小区 域都单独进行内存使用和垃圾回收,这样做的好处是可以根据每个小区域 内存的大小灵活使用和释放内存。
分区收集算法可以根据系统可接受的停顿时间,每次都快速回收若干个小区域的内存,以缩短垃圾回收时系统停顿的时间,最后以多次并行累 加的方式逐步完成整个内存区域的垃圾回收。
如果垃圾回收机制一次回收整个堆内存,则需要更长的系统停顿时间,长时间的系统停顿将影响系统
运行的稳定性
相关 VM 参数
含义
参数
堆初始大小
-Xms
堆最大大小
-Xmx
或
-XX:MaxHeapSize=size
新生代大小
-Xmn
或
(-XX:NewSize=size + -XX:MaxNewSize=size )
幸存区比例(动态)
-XX:InitialSurvivorRatio=ratio
和
-XX:+UseAdaptiveSizePolicy
幸存区比例
-XX:SurvivorRatio=ratio
晋升阈值 是指 新生区对象升级到老年代的最大寿命
-XX:MaxTenuringThreshold=threshold
晋升详情
-XX:+PrintTenuringDistribution
GC
详情
-XX:+PrintGCDetails -verbose:gc
FullGC
前
MinorGC
-XX:+ScavengeBeforeFullGC
四种引用
1. 强引用
只有所有 GC Roots
对象都不通过【强引用】引用该对象,该对象才能被垃圾回收
2. 软引用(SoftReference)
仅有软引用引用该对象时,在垃圾回收后,内存仍不足时会再次出发垃圾回收,回收软引用
对象
可以配合引用队列来释放软引用自身
3. 弱引用(WeakReference)
仅有弱引用引用该对象时,在垃圾回收时,无论内存是否充足,都会回收弱引用对象
可以配合引用队列来释放弱引用自身
4. 虚引用(PhantomReference)
必须配合引用队列使用,主要配合
ByteBuffffer
使用,被引用对象回收时,会将虚引用入队,
由
Reference Handler
线程调用虚引用相关方法释放直接内存
5. 终结器引用(FinalReference)
无需手动编码,但其内部配合引用队列使用,在垃圾回收时,终结器引用入队(被引用对象
暂时没有被回收),再由
Finalizer
线程通过终结器引用找到被引用对象并调用它的
fifinalize
方法,第二次
GC
时才能回收被引用对象

这篇博客也讲到了引用
ThreadLocal 使用 以及源码分析_m0_71149992的博客-优快云博客_thread数组