【JVM系列详解】jvm垃圾回收机制(上)——死亡对象判断和引用类型

学习过JVM内存结构后,我们知道,程序计数器和栈(虚拟机栈、本地方法栈)是线程私有的,程序计数器不会溢出,栈会在方法结束后自动出栈,因此不需要回收机制对其空间进行释放整理。但是堆和方法区不同,首先它们是线程共享的,会存放大量的对象,占用很多的空间;第二是它们没有和栈一样的自动出栈机制。所以就需要一种机制对其无用的对象进行释放整理,这种机制叫做垃圾回收机制

垃圾回收概述

垃圾回收主要就是分为两个问题:

  • 什么是垃圾?
  • 垃圾怎么回收?

关于第一个问题:什么是垃圾?

在JVM堆和方法区中,很显然,就是没用的对象就是“垃圾”,这些对象称为死亡对象。对于怎么判断对象“没用”了,就是垃圾回收机制中的第一块大内容:死亡对象判断方法

关于第二个问题:垃圾怎么回收?

这个问题,很多的研究人员就探讨出了很多的回收方法理论,这就是垃圾回收算法。需要注意的是这是从理论上方法,并且每种方法各有优劣,在实际情况下,会遇到各种的情况,只采用一种方法的话,难免会存在很大的局限性。针对不同的情况采用不同的算法,真正将算法落地和实现就是垃圾回收器要做的事。

因此,本系列将分别对死亡对象判断法、垃圾回收算法、垃圾回收器进行详述。
本文首先介绍死亡对象判断方法

垃圾回收算法见——【JVM系列详解】jvm垃圾回收机制(中)——垃圾回收算法

引用计数法

概念

给对象加一个引用计数器,每当有地方引用给对象,则计数器+1;每当一个地方引用失效,则计数器-1;当计数器为0时则视为死亡对象。

问题

这种方法实现简单,效率高,但是存在一个问题:对象循环引用问题。当两个对象彼此间互相引用对方,即使实际上并没有被真正使用,也不会导致计数器为0,就不会被回收。所以目前主流虚拟机并没有采用这种方法。

例如,这种情况的代码如下:

public class GCRootsExample {
    private Object reference;

    public static void main(String[] args) {
        // 创建两个互相引用的对象
        GCRootsExample obj1 = new GCRootsExample();
        GCRootsExample obj2 = new GCRootsExample();
        obj1.reference = obj2;
        obj2.reference = obj1;
        // 断开GC Roots的引用
        obj1 = null;
        obj2 = null;
        // 此时,虽然obj1和obj2互相引用,但它们与GC Roots(如栈中的局部变量)无关联
        // 引用计数法无法辨别这种情况
    }
}

可达性分析算法

概念

这种算法的思路是以一些“GC Roots”(称为根对象)为起点,建立一系列的引用链。在引用链上的对象则为有用对象,不在引用链上的对象,则为死亡对象,可以被回收。这种算法就不会出现循环引用问题,是目前常用的死亡对象判断方法。

GC Roots

那么哪些对象可以被称为根对象呢?可以作为根对象的为:

  • 虚拟机栈中引用的对象
  • 方法区中的静态属性引用的对象
  • 方法区中的常量引用的对象
  • 本地方法栈中引用的对象
  • 活跃线程对象
  • 同步锁持有的对象

引用类型总结

四大引用类型

无论是引用计数器判断引用的数量,还是可达性分析引用链,都涉及到引用。从JDK1.2后就分为了四大引用,其分别为:强引用、软引用、弱引用、虚引用

引用类型区别

引用类型回收特点引用队列相关
强引用不会被回收
软引用内存充足时不回收,不足时会被回收可以配合引用队列
弱引用无论内存是否充足都可能被回收可以配合引用队列
虚引用无论内存是否充足都可能被回收必须配合引用队列

弱引用和虚引用使用很少,目前比较常见的弱引用是ThreadLocal中使用了,虚引用可以用于监控一个对象是否被回收,例如NIO操作中使用了。

终结器(非标准)

终结器其实就是为了实现对象的finalize()方法存在的。这种是自动进行的,无需手动编码。

这种终结器机制需要配合引用队列实现:

  • 可达性分析法中不可达的对象第一次被标记入队,并且进行一次筛选:判断是否需要执行finalize方法。(不会执行的情况:当对象没有覆盖finalize方法,即还是Object的;或者finalize已经被调用过一次)
  • 如果重写了,则会创建一个Finalizer 线程对象,其通过终结器引用找到被引用对象并调用它的 finalize 方法。
  • 被判定为需要执行的对象将会被放在一个队列中进行第二次标记,除非这个对象与引用链上的任何一个对象建立关联,否则就会被真的回收。

总结

死亡对象判断和引用类型主要可以总结如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值