原文连接:https://blog.csdn.net/xiangzh...java
垃圾收集器通常完成两件事算法
一般,Java对象的引用能够分为4类:强引用、软引用、弱引用和虚引用。.net
强引用:一般能够认为是经过new出来的对象,即便内存不足,GC进行垃圾收集的时候也不会主对象
动回收。blog
Object obj = new Object();队列
软引用:在内存不足的时候,GC进行垃圾收集的时候会被GC回收。内存
Object obj = new Object(); SoftReference<Object> softReference = new SoftReference<>(obj);get
弱引用:不管内存是否充足,GC进行垃圾收集的时候都会回收。虚拟机
Object obj = new Object(); WeakReference<Object> weakReference = new WeakReference<>(obj);效率
虚引用:和弱引用相似,主要区别在于虚引用必须和引用队列一块儿使用。
Object obj = new Object();
ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
PhantomReference<Object> phantomReference = new PhantomReference<>(obj, referenceQueue);
引用队列:若是软引用和弱引用被GC回收,JVM就会把这个引用加到引用队列里,若是是虚引用,在回收前就会被加到引用队列里。
引用计数法:给每一个对象添加引用计数器,每一个地方引用它,计数器就+1,失效时-1。若是两个对象互相引用时,就致使没法回收。
可达性分析算法:以根集对象为起始点进行搜索,若是对象不可达的话就是垃圾对象。根集(Java栈中引用的对象、方法区中常量池中引用的对象、本地方法中引用的对象等。JVM在垃圾回收的时候,会检查堆中全部对象是否被这些根集对象引用,不可以被引用的对象就会被垃圾回收器回收。)
常见的垃圾回收算法有:
标记-清除
标记:首先标记全部须要回收的对象,在标记完成以后统计回收全部被标记的对象,它的标记过程即为上面的可达性分析算法。
清除:清除全部被标记的对象
缺点:
效率不足,标记和清除效率都不高
空间问题,标记清除以后会产生大量不连续的内存碎片,致使大对象分配没法找到足够的空间,提早进行垃圾回收。
复制回收算法
将可用的内存按容量划分为大小相等的2块,每次只用一块,当这一块的内存用完了,就将存活的对象复制到另一块上面,而后把已使用过的内存空间一次清理掉。
缺点:
将内存缩小了本来的通常,代价比较高
大部分对象是“朝生夕灭”的,因此没必要按照1:1的比例划分。
如今商业虚拟机采用这种算法回收新生代,但不是按1:1的比例,而是将内存区域划分为eden 空间、from 空间、to 空间 3 个部分。
其中 from 空间和 to 空间能够视为用于复制的两块大小相同、地位相等,且可进行角色互换的空间块。from 和 to 空间也称为 survivor 空间,即幸存者空间,用于存放未被回收的对象。
在垃圾回收时,eden 空间中的存活对象会被复制到未使用的 survivor 空间中 (假设是 to),正在使用的 survivor 空间 (假设是 from) 中的年轻对象也会被复制到 to 空间中 (大对象,或者老年对象会直接进入老年带,若是 to 空间已满,则对象也会直接进入老年代)。此时,eden 空间和 from 空间中的剩余对象就是垃圾对象,能够直接清空,to 空间则存放这次回收后的存活对象。这种改进的复制算法既保证了空间的连续性,又避免了大量的内存空间浪费。
标记-整理
在老年代的对象大都是存活对象,复制算法在对象存活率教高的时候,效率就会变得比较低。根据老年代的特色,有人提出了“标记-压缩算法(Mark-Compact)”
标记过程与标记-清除的标记同样,但后续不是对可回收对象进行清理,而是让全部的对象都向一端移动,而后直接清理掉端边界之外的内存。
这种方法既避免了碎片的产生,又不须要两块相同的内存空间,所以,其性价比比较高。
分带收集算法
根据对象存活的周期不一样将内存划分为几块,通常是把Java堆分为老年代和新生代,这样根据各个年代的特色采用适当的收集算法。
新生代每次收集都有大量对象死去,只有少许存活,那就选用复制算法,复制的对象数较少就可完成收集。
老年代对象存活率高,使用标记-压缩算法,以提升垃圾回收效率。
点击下方连接免费获取Android进阶资料: