欢迎来到天天文库
浏览记录
ID:40917743
大小:149.89 KB
页数:7页
时间:2019-08-10
《垃圾收集器与内存分配策略》由会员上传分享,免费在线阅读,更多相关内容在教育资源-天天文库。
1、垃圾收集器与内存分配策略一、如何判断对象是否还在存活1.引用计数法:主流的Java虚拟机没有使用这种方法管理内存,因为它很难解决循环依赖2.可达性分析:通过一系列的称为”GC Roots“的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GCRoots没有与任何引用链相连时,则证明该对象是不可用的。作为GCRoots的对象包括以下几种:虚拟机栈中引用的对象、方法区中类静态属性引用的对象、方法区中常量引用的对象以及本地方法栈中JNI引用的对象。二、引用:•定义:如果reference类型的数据中存储的数值代表的是另外一块内存的起始地址,就称这块内存代
2、表着一个引用。•分类:强引用:代码之中普遍存在的,如Objectobj=newObject(),只要强引用还在,GC就永远不会回收该内容。软引用:描述有用但非必须的对象。对于软引用关联着的对象,在系统将要抛出内存异常之前,会将这些对象列进回收范围进行二次回收。如果这次回收还没有足够的内存,才会抛出异常。(SoftReference)弱引用:弱引用也用来描述非必须的对象。被若引用关联的对象只能活到下次垃圾回收发生之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。虚引用:又称为幽灵引用或者幻影引用。一个对象是否有虚引用的存在,丝毫不会影响对象的生存时间,
3、也不能通过虚引用获得对象实例。为一个对象设置虚引用关联的唯一目的就是能在这个对象被垃圾收集器回收时收到一个系统通知。三、对象标记之后就会回收吗•可达性分析之后,没有在任何GCRoots引用链上的对象,就会被第一次标记,标记之后还有一次筛选的过程;•筛选的条件是:此对象是否有必要执行finalize方法,有必要执行的条件是:该对象覆盖了finalize方法,并且没有虚拟机调用过,也就是说任何一个对象的finalize方法都只会被系统执行一次。•如果有必要执行finalize方法,该对象则将会被放置一个成为F_Queue的队列之中,并在稍后由一个有虚拟机自动建立的、低优先级的Fina
4、lizer线程去触发该方法。但不会等待finalize执行结束。•finalize方法是对象逃脱死亡命运的最后一次机会。稍后GC将对F_Queue中的对象进行第二次小规模的标记,如果能与引用链上任何一个对象建立关系,对象就不会被再次标记,从而活下来。•注:如果没有必要执行finalize对象,是不是就会立即被GC回收呢四、方法区的回收•在堆中,尤其是新生代中,常规应用进行一次垃圾收集一般可以回收70%~95%的空间,而永久代的垃圾收集效率远低于此。•永久代中的垃圾收集主要回收两部分内容:废弃常量和无用的类•废弃常量:当前系统中没有任何一个对象引用该常量。•无用的类:该类所有的实例
5、都已被回收(Java堆中不存在该类的任何实例)、加载该类的ClassLoader被回收、该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。五、垃圾收集算法• 1、标记-清除算法: 首先是标记出所有需要回收的对象,在标记完成后回收所有被标记的对象。 缺点:•效率问题:标记和清楚两个过程的效率都不高•空间问题:标记清除之后会造成大量不连续的内存碎片,空间碎片太多导致需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾回收动作。 2、复制算法: 描述
6、:将可用内存按容量划分为两块,每次只是用其中的一块,当这一块内存用完了,就将还存活的对象复制到另外一块内存,然后再把已使用过的内存空间一次性的清理掉。 优点:不用考虑内存碎片 缺点:内存缩小为原来的一半 应用:目前的商业虚拟机都采用这种收集算法来回收新生代,具体如下: 将内存分为一块较大的Eden空间和两块较小的Survivior空间,每次使用Eden和其中一个Survivior空间。 当回收时,将Eden区和Survivior中还存活着的对象一次性的复制到另外一块Survivior空间上,最后清理Eden区和另一块S
7、urvivior区。 Hotspot虚拟机默认Eden和Survivior的大小比例是8:1 当另外一块Survivior空间没有足够的空间存放上一次新生代存活的对象时,这些对象将直接通过分配担保机制进入老年代。 3、标记-整理算法: 标记之后,让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。 4、分代收集算法: 当前虚拟机的垃圾收集都采用”分代收集“算法。一般是把Java堆分为新生代和老年代;
此文档下载收益归作者所有