文中讨论的GC原理均基于 Sun Hotspot JVM,对于不一样 JVM 实现可能会有不一样。算法
决定哪些内存须要回收(物理内存的位置)。框架
决定什么时候回收这些内存。线程
决定以什么方式(算法)回收这些内存代理
##2. GC 回收的不一样区域code
##3. GC 回收对象 的依据 : 对象存活算法对象
引用计数算法接口
每一个对象关联一个引用计数器,当有引用就加1,引用失效时减一,引用为0说明对象可回收
对象循环互相引用不能检测,指的是,多个对象之间互相引用,可是这多个对象与其余外界再也不具有任何访问条件的现象
根搜索算法生命周期
从一系列 GCRoot 对象向下搜索,搜索走过的路径叫作引用链,当某个对象不能经过引用链被搜索到,就说明可回收
总结队列
大多数虚拟机采用的是跟搜索算法
##3. GC 引用的分类内存
强引用
使用 new 关键字实例化赋值的对象与变量之间的关系叫作强引用
只要强引用存在,就永远不会被回收
软引用
描述有做用,但非必需的对象,使用 SoftReference 类来定义
在系统发生内存溢出以前,会被归入回收范围以内并进行第二次回收
弱引用
比软引用更弱的引用类型,使用 WeakReference 类来定义
只能存活到下一次垃圾收集发生以前(不管时候内存溢出)
虚引用
最弱的引用类型,虚引用至关于对象的生命周期是透明的(不会延长对象的生命周期),甚至没法经过虚引用得到对象的实例,惟一的目的就是在被回收的时候收到一个系统通知,使用 PhantomReference 类来定义
至关于不存在,不影响回收时机
##3. GC 回收对象的全过程
堆内存的回收
根据存活算法扫描到某个对象A已经不被引用并进行第一次标记
第一次标记以后,筛选该对象是否有必要执行 finalize() 方法,执行的条件是该对象覆盖了finalize() 方法,而且finalize() 方法未被调用过。
若是没有必要执行finalize() 方法
若是有必要执行finalize()方法,该对象被放置到一个F-QUEUE队列中,并在一个虚拟机线程去执行,执行的过程当中,只保证触发这个方法,不保证等待方法运行结束(防止时间过长、死循环 致使GC回收机制崩溃)
GC 进行第二次扫描,若是发现再次发现对象A 不被引用,那么就将执行回收过程;这里若是对象A在步骤 4 中执行finalize() 方法的时候,在代码里面从新与GCRoot引用链得到的访问关系,此次扫描将不会被扫描到,可是由于finalize()已经被执行过了,因此下次一旦被扫描到,就不能再经过finalize()来GC逃逸了
方法区内存的回收
回收特色: 方法区内存主要回收废弃,不用的 常量,类,接口
回收常量: 加入对于某个常量池中的字符串,已经没有任何该类型(String)的对象是这个值,也没有其余地方引用到了这个字面量,若是这个时候发生内存回收,并且有必要(这个根据情具体实现况判断什么是有必要,好比常量的生命时间,常量的使用频率等),这个常量将被回收
-回收类(包括它的接口,方法名,字段): 1. 该类的实例对象都已经被回收
2. 加载该类的ClassLoader也已经被回收
3. 该类的Class 对象没有被任何地方引用,也就是没法经过反射来访问这个类
4. 当知足了上述3个条件,仅仅是说明能够回收了,不表明会回收,具体看不一样虚拟机的限定条件
5. 类回收的主要场景: 对于应用大量 反射,动态代理,CGLib 等bytecode的框架以及场景,动态生成JSP和OSGI等频繁定义用户ClassLoader的场景,都有可能产生大量的自动生成的类加载行为,为了防止永久区溢出,须要对这种生成的类进行卸载