一、判断垃圾对象的方法
public class ReferenceCountingGc {
Object instance = null;
public static void main(String[] args) {
ReferenceCountingGc objA = new ReferenceCountingGc();
ReferenceCountingGc objB = new ReferenceCountingGc();
objA.instance = objB;
objB.instance = objA;
objA = null;
objB = null;
}
}
2. 本地方法栈JNI(Java Native Interface)引用的对象
3. 方法区类静态属性引用的对象
4. 方法区常量池引用的对象
5. 活跃线程引用的对象
二、常见引用类型
public static User user = new User();
软引用:将对象用SoftReference软引用类型的对象包裹,正常情况不会被回收,但是GC做完后发现释放不出空间存放新的对象,则会把这些软引用的对象回收掉。软引用可用来实现内存敏感的高速缓存。
public static SoftReference<User> user = new SoftReference<User>(new User());
public static WeakReference<User> user = new WeakReference<User>(new User());
三、finalize()方法最终判定对象是否存活
四、如何判断一个类是无用的类
五、垃圾回收算法
分代收集算法
按照对象生命周期的不同划分区域以采用不同的垃圾回收算法。几乎所有的Java堆都采用这种算法。
复制算法
将内存划分为对象面和空闲面。当对象面的内存用完时,就将对象面中活中的对象复制到空闲面内存中,然后将对象面的对象内存清除。
特点:不会产生内存碎片,由于是使用连续的内存分配来分配,使得它简单高效,“标记-清除”或“标记-整理”算法会比复制算法慢10倍以上。复制算法适用于对象存活率低的场景,比如年轻代的垃圾回收。需用使用备份内存来处理发生空闲面内存不够用的情况。
标记-清除算法
用可达性算法找到垃圾对象进行标记后,会对堆内存从头到尾进行线性遍历,回收不可达的对象。然后将原来标记为可达对象的标识给清除,以便下一次回收。
缺点:效率较低,无论是标记和清除的效率都不高。容易造成内存碎片化,当有大对象需要分配空间时,容易造成无法找到足够大的连续内存而触发另一次GC.
标记-整理算法
用可达性算法找到垃圾对象进行标记后,移动所有存活的对象,且按照内存地址次序排序,然后将末端内存地址以后的内存全部回收。它回收成本更高,但是不产生内存碎片。适用于对象存活率较高的场景。
六、垃圾收集器
1.1 Serial收集器(-XX:+UseSerialGC -XX:+UseSerialOldGC)
![](https://i-blog.csdnimg.cn/blog_migrate/bcac3de40deb727eb3497accdcc2ca80.png)
1.2 Parallel Scavenge收集器(-XX:+UseParallelGC(年轻代),-XX:+UseParallelOldGC(老年代))
![](https://i-blog.csdnimg.cn/blog_migrate/0f5e3e0519155b45afaceee7a14ada1d.png)
1.3 ParNew收集器(-XX:+UseParNewGC)
![](https://i-blog.csdnimg.cn/blog_migrate/62a7cb38e8e17ebd124abca167f898f4.png)
1.4 CMS收集器(-XX:+UseConcMarkSweepGC(old))
![](https://i-blog.csdnimg.cn/blog_migrate/cd2bb6b4b7a551b5acc26cbf6add9735.png)
七、垃圾收集底层算法实现
三色标记
多标-浮动垃圾
多标只在垃圾收集过程中由于工作线程在并发执行,导致垃圾对象被当作非垃圾对象标记的情况,因多标而产生的浮动垃圾只能在下一次GC时回收。多标在并发标记和并发清理两阶段发生,有两种情况:一、已经扫描过被标记为非垃圾对象在这阶段被当作垃圾释放,此时会当做非垃圾对象处理。二、产生了新对象,也会当作非垃圾对象处理。
漏标-读写屏障
漏标会导致非垃圾对象被当作垃圾对象回收,属于严重bug。有两种处理方式:
增量更新:一个黑色对象添加了一个白色对象的引用,则将这个引用加入一个集合中,同时黑色对象变成灰色对象。在重新标记阶段,会对灰色对象重新扫描。
原始快照:一个灰色对象对白色对象的引用被删除时,这个引用关系也会被存入一个集合中。在重新标记阶段,会根据这个引用关系找到白色对象,同时将白色对象变为黑色对象,避免被当作垃圾回收。当然,这个过程也可能会产生浮动垃圾。
增量更新和原始快照是处理漏标的两种方式,一般在垃圾收集器中只有其中一种方式存在。它们都是通过写屏障实现的。所谓的写屏障,其实就是指在赋值操作前后,加入一些处理。如新增引用的时候在引用完后采用写后屏障记录,删除引用前采用写前屏障记录。