GC(垃圾回收机制)

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)分代收集算法:根据对象的生命周期将内存划分为几块,然后根据各块的特点采用最适当的收集算法。大批对象死去、少量对象存活的(新生代)采用复制算法,复制成本低; 对象存活率高、没有额外空间分配担保的(老年代)采用标记-清理或标记-整理算法。

猜你喜欢

转载自blog.csdn.net/weixin_43766090/article/details/84891012