目录:java
1.为何要了解垃圾回收机制?算法
2.哪几类内存须要进行垃圾收集?并发
3.如何判断对象“已死”?——两种算法高并发
4.引用的细分this
5.对象的自救spa
1.为何要了解垃圾回收机制?线程
当须要排查各类内存溢出、内存泄漏问题时,当垃圾收集成为系统达到更高并发了的瓶颈时,咱们就须要对这些“自动化”技术实施必要的监控和调节。对象
2.哪几类内存须要进行垃圾收集?接口
java运行时内存中,程序计数器、虚拟机栈、本地方法栈3个区域是线程私有的,随线程而生,随线程而灭;而Java堆和方法区则不同,一个接口中的多个实现类须要的内存可能不同,一个方法中的多个分支须要的内存也可能不同,咱们只有在程序处于运行期间才能知道会建立哪一个对象,这部份内存的分配和回收都是动态的,垃圾收集器关注的也是这部份内存。队列
3.如何判断对象“已死”?
引用计数算法:
来记录一个对象被引用的次数,当引用计数器为0时,表明这个对象再也不被使用。
优势:实现简单,判断效率也很高。
缺点:它很难解决对象之间相互循环引用的问题。
可达性分析算法:
在主流的商用程序语言的主流实现都是经过可达性分析来判断对象是否存活的。这个算法的基本思路就是经过一系列的称为“GC Roots”的对象做为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用相连时,证实此对象是不可用的。
java语言中,可做为GC Roots的对象包括下面几种:
①虚拟机栈(栈帧中的本地变量表)中引用的对象。
②方法区中静态属性引用的对象。
③方法区中常量引用的对象。
④本地方法栈中JNI(即通常说的Native方法)引用的对象。
4.引用的细分:
java中的引用定义很传统:若是reference类型的数据中存储的数值表明的是另一块内存的起始地址,就称这块内存表明着一个引用。这种定义很纯粹,可是太过狭隘,一个对象在这种定义下只有被引用或者没有被引用两种状态,对于如何描述一些“食之无味,弃之惋惜”的对象就显得无能为力。
咱们但愿能描述这样一组对象:当内存空间还足够时,则可以保存在内存中;若是内存空间在进行垃圾收集后仍是很是紧张,就能够抛弃这些对象。
在JDK1.2以后,java对引用的概念进行了扩充,将引用分为强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)4种。
强引用:就是指在程序代码之中广泛存在的,相似“Object obj=new Object()”这类引用,只要强引用还在,垃圾收集器永远不会回收掉被引用的对象。
软引用:是用来描述一些还有用但并不是必须的哦对象。对于软引用关联着的对象,在系统将要发生的内存溢出异常以前,将会把这些对象列进回收范围之中进行第二次回收,若是此次回收尚未足够的内存,才会抛出内存溢出的异常。
弱引用:也是用来描述非必须对象的,可是他的强度比软引用更弱一点,只能生存到下一次垃圾收集以前。
虚引用:最弱的引用关系,彻底不会对其生存时间构成影响,也没法经过虚引用来取得一个对象的实例。为一个对象设置虚引用的惟一目的就是可以在这个对象被收集器回收时收到一个系统通知。
5.对象的自救
即便在可达性分析算法中不可达的对象,也并不是是“非死不可”的,这时候他们暂时处于“缓刑”阶段,要真正宣告一个对象死亡,至少要经历两次标记过程:若是对象在进行可达性分析后发现没有与GC Roots相链接的引用链,那它将会被第一次标记而且进行一次筛选,筛选的条件是对此对象是否有必要执行finalize()方法。
当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过(对象自救机会只有一次),虚拟机将这两种状况都视为“没有必要执行”。
若是这个对象被断定为有必要执行的finalize()方法,那么这个对象将会被放置在一个叫作F-Queue的队列之中,并在稍后由一个由虚拟机自动创建的、低优先级的Finalize线程去执行它。这里所谓的“执行”是指虚拟机会触发这个方法,但并不承诺会等待它运行结束,这样作的缘由是,若是一个对象在finalize()方法中执行缓慢,或者发生了死循环,极可能回到藕汁F-Queue队列中的其余对象永久处于等待状态,甚至致使整个内存回收系统崩溃。
Finalize()方法是对象逃脱死亡命运的最后一次机会,稍后GC将堆F-Queue中的对象进行第二次小规模的标记,若是对象要在finalize()中成功拯救本身——只须要从新与引用链的任何一个对象创建关联便可,譬如把this赋值给某变量或者对象的成员变量,拿在第二次标记时,它将被移除出“即将回收”的集合;若是对象这个时候还有逃脱,那基本上他就真的被回收了。