一、如何判断对象可以回收?
1. 引用计数法:只要一个对象被其他变量所引用,就让计数加一,引用两次就让计数变为2,取消引用就让计数减一,但是这种算法有严重的弊端,如果两个变量之间循环引用的话,他们永远无法被垃圾回收。
2,可达性分析:通过一系列被称为「GC Roots」的根对象作为起始节点集,从这些节点开始,通过引用关系向下搜寻,搜寻走过的路径称为「引用链」,如果某个对象到GC Roots没有任何引用链相连,就说明该对象不可达,即可以被回收。
垃圾回收时,JVM首先要找到所有的GC Roots,这个过程称作 「枚举根节点」 ,这个过程是需要暂停用户线程的,即触发STW。
然后再从GC Roots这些根节点向下搜寻,可达的对象就保留,不可达的对象就回收。
哪些对象可以作为GC Roots?
1、方法区静态属性引用的对象
2、方法区常量池引用的对象
3、方法栈中栈帧本地变量表引用的对象
4、本地方法栈中引用的对象
5、被同步锁持有的对象
怎么查看根对象有哪些?
可以用Eclipse推出的Memory Analyzer(MAT)工具,先通过jmap生成一个内存快照,然后用MAT工具去分析该快照
二、引用类型:强软弱虚 + (终结器引用)
强引用:平时用的都是强引用,如果A对象没有被GC root直接或间接的强引用,A对象就可以被垃圾回收
软引用:如果A对象只被软引用所引用,如果下一次垃圾回收时发现内存仍然不够,就会把软引用引用的A对象也回收。
弱引用:如果A对象只被弱引用所引用,在下一次垃圾回收时就会回收A对象
虚引用:如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收,它不能单独使用也不能通过它访问对象,虚引用必须和引用队列(RefenenceQueue)联合使用。虚引用的主要作用是跟踪对象垃圾回收的状态。仅仅是提供了一种确保对象被 finalize 以后,做某些事情的机制。
换句话说,设置虚引用的唯一目的,就是在这个对象被回收器回收的时候收到一个系统通知或者后续添加进一步的处理。
*终结器引用:和对象的finalize()方法有关,如果一个对象重写了finalize方法,虚拟机会给对象创建一个终结器引用,当对象第一次被垃圾回收的时候会把终结器引用放到引用队列中,再由一个优先级很低的线程,叫做finalize handler线程,在某些时机去查看引用队列中有没有终结器引用,有的话就会去调用对象的finalize()方法,执行完方法后,在下一次垃圾回收时才会把对象真正回收掉。
这里可以发现finalize()的效率很低,第一次垃圾回收时不能把对象真正回收掉,而是把终结器放到引用队列,而且finalize handler的优先级很低,可能导致该对象的finalize()方法迟迟不被执行,对应内存也不能被回收。所以一般不推荐使用finalize()方法。
三、垃圾回收算法
1,标记清楚算法: Mark Sweap
第一步:先标记,根据GC Root扫面堆中对象,标记出没有被直接或间接引用的对象,可以被回收。
第二步:后清除,将第一步标记的区域进行释放,*注意,这里释放不是指把每个区域的字节进行清零,而是把对象的起始和结束地址放到空闲地址列表中,下次分配新地址的时候就到空闲地址列表中去找有没有一块足够的空间容纳新对象。
优点:速度快,只需要记录对象的起始和结束地址。
缺点:没有整理工作,容易产生内存碎片。
2,标记整理算法:Mark Compact
第一步:和标记清除算法一样,标记出垃圾
第二步:将剩余的存活对象进行整理,把可用的对象向前移动,使内存更为紧凑。
优点:无内存碎片,有连续的内存空间可用
缺点:由于牵扯对象的移动,地址变了,需要改变对象的引用地址,效率较低
3,复制算法 Copy
第一步:也是标记出未被引用的空间、
第二步:将from中存活的空间移动到to中,清楚from中所有的空间
第三步:将from和to的位置调换,to的空间始终空闲
缺点:占用双倍的内存空间
以上三种算法在JVM中都会用到,在实际中根据不同情况来采用。
四、分代回收算法
新对象都会被存放在Eden区中,当Eden区满了会触发新生代GC(Minor GC),因为新生代中大多数对象的生命周期都很短,所以发生Minor GC的频率很高,虽然它会触发stop-the-world,但是它的回收速度很快。
每次Minor GC都把不需要回收和幸存区留下的采用复制算法移到To中,然后交换From和To的位置,记录每个对象的年龄,没被回收的话,年龄+1,如果一个对象经历了15次GC都没被回收,就会被放入老年代。*另外,如果幸存区空间紧张时,或者要存放一个大小超过幸存区的大对象,该对象会被直接存放在老年代。
如果新生代和老年代都接近满了,存不下新对象,就会触发Full GC,对新生代和老年代整个进行清理。
五,垃圾回收器
5.1 分类:
串行: 单线程,堆内存较小,适合个人电脑
吞吐量优先: 多线程,堆内存较大,多核CPU,让单位时间内STW的时间最短 0.2,0.2 = 0.4
相应时间优先:多线程,堆内存较大,多核CPU,尽可能让单次的STW时间最短 0.1,0.1,0.1,0.1,0.1 = 0.5
标签:finalize,对象,回收,GC,垃圾,JVM,引用 From: https://www.cnblogs.com/tyleaf/p/17071167.html