1、为什么要垃圾回收?
如果只消耗内存不进行垃圾回收,内存迟早会被消耗完,除非内存无限大,但这是不可能的。
2、如何找到需要被回收的对象?
引用计数法:给对象添加一个计数器,被引用时计数器+1,引用失效时计数器-1,当计数器为0时回收。但是java没有使用这种方法,因为很难解决对象间相互引用的问题。
可达性分析法:通过一系列称为"GC Roots"的对象作为起始点,从这些起始点向下搜索,这些被搜索过的路径称为引用链,当一个对象到GC Roots之间没有任何引用链时,证明此对象是不可用的。
java语言中可以作为GC Roots的对象包括:
(1) 虚拟机栈(栈帧中的局部变量区,也叫局部变量表)中引用的对象;
(2) 方法区中的类静态属性引用的对象;
(3) 方法区中常量引用的对象;
(4) 本地方法栈中native方法引用的对象。
3、四种引用状态:
强引用(StrongReference):代码中普遍存在的类似于"Object obj = new Object()"这类的引用,只要强引用存在,垃圾收集器就不会回收掉该对象。
软引用(SoftReference):描述有些还有用但非必需的对象,将在内存即将溢出时回收掉。
弱引用(WeakReference):描述非必需的对象,它和软引用的区别是只能生存到下一垃圾回收之前。在垃圾收集器线程(优先级非常低的线程)发现弱引用时,不论内存是否已满都会回收。
虚引用(PhantomReference):唯一目的就是在被回收时会有系统通知,用来跟踪对象被垃圾收集器回收的活动。虚引用必须和引用队列联合使用。
注意:对于可达性分析算法而言,要想回收对象至少要经历两次标记阶段:
1)、如果对象在进行可达性分析后没有发现和GC Roots相连的引用链,则该对象被第一次标记并进行一次筛选,筛选条件为是否有必要执行该对象的finalize方法。如果该对象没有重写finalize方法或该对象已经执行过一次finalize方法则该对象会被回收,反之则不会被回收,这个对象会被放在F-Queue的队列中。
2)、对F-Queue对象进行第二次标记如果该对象在finalize方法中关联上GCRoots引用链(如把this关键字赋值给其他变量),则在第二次标记的时候对象将从"即将回收"的集合中移除。如果对象finalize方法并没有关联则就会被回收。
4、方法区的垃圾回收:废弃常量和无用的类
废弃常量:如果一个常量已经进入了常量池,但是当前系统没有一个对象使用了该常量,那么发生垃圾回收并且有必要时该常量就会被移除常量池。常量池中的其他类(接口)、方法、字段的符号引用也与此类似。
无用的类:(1) 该类的所有实例都已被回收,即java堆中不存在该类的任何实例。
(2) 加载该类的ClassLoader 方法已被回收。
(3) 该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过放射访问该对象的方法。
5、垃圾回收算法:
(1) 标记清除算法:分"标记"和"清除"两个阶段,首先标记出所有需要回收的对象,最后统一回收。
缺点:标记和清除两个过程效率都不高,而且会产生大量的不连续内存碎片,使得分配较大对象时无法找到内存空间。
(2)复制算法:将内存分为两块,每次只用一块,每当一块用完了就将活着的对象复制到另外一块上面,然后再把使用过的空间清理。
缺点:内存缩小为原来的一半,代价很高。
(3) 标记整理算法:让所有存活对象都向一端移动,然后直接清理掉边界以外的内存。
(4)分代收集算法:根据对象的生命周期将内存划分为几块,然后根据各块的特点采用最适当的收集算法。大批对象死去、少量对象存活的(新生代)采用复制算法,复制成本低; 对象存活率高、没有额外空间分配担保的(老年代)采用标记-清理或标记-整理算法。
GC(垃圾回收机制)
猜你喜欢
转载自blog.csdn.net/weixin_43766090/article/details/84891012
今日推荐
周排行