「这是我参与11月更文挑战的第15天,活动详情查看:2021最后一次更文挑战」
一、 GC的原理和回收策略
1. 垃圾分类
(1) 强引用(StrongPeference 非垃圾)
本身现在不是垃圾,new创建的对象即使抛出OOM异常,也不会进行回收
(2) 软引用(SoftReference 可能是垃圾)
内存不足时,才是垃圾
(3) 弱引用(WeakPeference 垃圾)
下一次GC回收
(4) 虚引用(PhantomReference 垃圾)
一个对象是否有虚引用的存在,不会对其生存时间造成影响,也无法通过虚引用得到一个对象,(目的就是为了回收finalize)
为对象设置虚引用的唯一目的就是能在这个对象被回收时收到一个系统通知
2. 定义是否是垃圾****
1) 引用计数
对象头中分配一个空间来保存该对象被引用的次数(Reference Count)。如果该对象被其它对象引用,则它的引用计数加1,如果删除对该对象的引用,那么它的引用计数就减1,当该对象的引用计数为0时,那么该对象就会被回收
2) 可达性分析
通过垃圾回收根(GC Roots)的对象作为起点,从这些节点开始向下搜索,搜索走过的路径被称为引用链(Reference Chain),当一个对象到 GC Roots 没有任何引用链相连时(即从 GC Roots 节点到该节点不可达),则证明该对象是不可用的
通过可达性算法,成功解决了引用计数所无法解决的问题-“循环依赖”,只要你无法与 GC Root 建立直接或间接的连接,系统就会判定你为可回收对象。那这样就引申出了另一个问题,哪些属于 GC Root
在 Java 语言中,可作为 GC Root 的对象包括以下4种:
l 虚拟机栈(栈帧中的本地变量表)中引用的对象
l 方法区中类静态属性引用的对象
l 方法区中常量引用的对象
l 本地方法栈中 JNI(即一般说的 Native 方法)引用的对象
3. 如何回收垃圾
1) 标记-清除
l 标记:检查每个对象是否为活对象
l 清除:将可回收对象回收,并且去除标记(定点清除)
l 标记和清除过程效率都不高,会产生大量不连续的内存碎片,导致无法给大对象分配内存
2) 复制算法
将内存划分为大小相等的两块,每次只使用一块,当一块内存使用完,就将存活对象复制到另一块,并且清理当前内存块
3) 标记-整理
让所有存活的对象都向一端移动,然后直接清理掉端边界以为的内存
优点:不会产生内存碎片
缺点:内存移动频繁,效率低
4) 分代收集算法
新生代使用:复制算法-存活对象转移到from或者直接到old
老年代使用:标记-整理
From和To区轮换,可以保证总有一个区是空的,提高效率
5) 方法区的回收
对这块区域进行垃圾回收的主要目的是对常量池的回收和对类的卸载,但是一般比较难实现