首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JVM系列--彻底搞清楚怎么确定一个对象是垃圾对象?

JVM系列--彻底搞清楚怎么确定一个对象是垃圾对象?

作者头像
田维常
发布2020-04-22 11:33:29
5470
发布2020-04-22 11:33:29
举报

关注Java后端技术栈”

回复“面试”获取最新资料

本文内容

如何确定一个对象是垃圾对象?

对于一部分人来说先搞清楚,对象与对象引用到底是什么区别?

Java是面向对象编程的语言,都说在Java世界里万事万物皆对象。

类的声明周期和对象的声明周期。关于类的声明周期请看:JVM系列——java文件到JVM中的整个过程

对象的生命周期

下面大致说说对象的生命周期。

创建阶段

在创建阶段有几个步骤完成对象的创建:

  • 为对象分配存储空间
  • 开始构造对象
  • 从超类到子类对static成员进行初始化
  • 超类成员变量按顺序初始化,递归调用超类的构造方法
  • 子类成员变量按顺序初始化,子类构造方法调用

一旦对象被创建,并被分派给某些变量赋值,这个对象的状态就切换到了应用阶段

应用阶段

该对象应该至少被一个强引用持有着。

可以见阶段

当一个对象处于不可见阶段时,说明程序本身不再持有该对象的不论什么强引用,尽管该这些引用仍然是存在着的。简单说就是程序的运行已经超出了该对象的作用域了。

不可达阶段

对象处于不可达阶段是指该对象不再被不论什么强引用所持有。

与“不可见阶段”相比,“不可见阶段”是指程序不再持有该对象的不论什么强引用,这样的情况下,该对象仍可能被JVM等系统下的某些已装载的静态变量或线程或JNI等强引用持有着,这些特殊的强引用被称为”GC root”。存在着这些GC root会导致对象的内存泄露情况,无法被回收。

收集阶段

当垃圾回收器发现该对象已经处于“不可达阶段”而且垃圾回收器已经对该对象的内存空间又一次分配做好准备时,则对象进入了“收集阶段”。假设该对象已经重写了finalize()方法,则会去运行该方法的终端操作。

这里要特别说明一下:不要重载finazlie()方法!finial方法来自Object中。参考:

原因有两点:

  • 会影响JVM的对象分配与回收速度

在分配该对象时,JVM需要在垃圾回收器上注冊该对象,以便在回收时可以运行该重载方法;在该方法的运行时需要消耗CPU时间且在运行完该方法后才会又一次运行回收操作,即至少需要垃圾回收器对该对象运行两次GC。

  • 可能造成该对象的再次“复活”

在finalize()方法中,假设有其他的强引用再次持有该对象,则会导致对象的状态由“收集阶段”又又一次变为“应用阶段”。这个已经破坏了Java对象的生命周期进程,且“复活”的对象不利用兴许的代码管理。

终结阶段

当对象运行完finalize()方法后仍然处于不可达状态时,则该对象进入终结阶段。在该阶段是等待垃圾回收器对该对象空间进行回收。

对象空间又一次分配阶段

垃圾回收器对该对象的所占用的内存空间进行回收或者再分配了,则该对象彻底消失了,称之为“对象空间又一次分配阶段”。

Java对象的四大引用

先来了解对象的四大引用方式:

JDK从1.2开始增加了多种引用方式:软引用、弱引用、虚引用 。

强引用
    /**
     * /强引用
     */
    private void strangeReference() {
        String str = new String("");
        System.out.println(str);
        UserVo [] userVo = new UserVo[1000000000];
        System.out.println(userVo.toString());
    }

方法中就算内存不够了而导致OOM,也不会进行回收这种引用。也是我们平时对象使用方式最多的方式。

弱引用
/**
 * 软引用
 */
private void softReference() {
    Object obj = new Object();
    SoftReference<Object> sf = new SoftReference<Object>(obj);
    System.out.println(sf.toString());
}

如果一个对象具有软引用,内存足够GC就不会回收它,内存不足时就会回收这些对象的内存,故可以防止内存 泄露,增强代码的健壮性 。软引用用来实现内存敏感的高速缓存,比如说:网页缓存、图片缓存等。

软引用
    /**
     * 弱引用
     */
    private void weakReference() {
        String str = new String("abc");
        WeakReference<String> abcWeakRef = new WeakReference<String>(str);
    }

弱引用也是用来描述非必需对象的,当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。在Java中,用java.lang.ref.WeakReference类来表示。

经典实用案列java.langThreadLocal

ThreadLocal相关请参考: ThreadLocal造成内存溢出OOM面试再问ThreadLocal,别说你不会 再谈ThreadLocal ThreadLocal&nbsp;面试六连问,中高级必问

虚引用
    /**
     * 虚引用
     */
    private void phantomReference() {
        String str = new String("abc");
        ReferenceQueue<String> rq = new ReferenceQueue<String>();
        PhantomReference<String> phantomRef = new PhantomReference<String>(str, rq);
    }

如果一个对象仅持有虚引用,那么它就和没有引用一样,在任何时候都可以被垃圾回收期收回 作用:跟踪对象被垃圾回收器回收的活动。

如何确定一个对象是垃圾对象?

要想进行垃圾回收,得知道什么样的对象是垃圾。

引用计数法

对于某个对象而言,只要应用程序中持有该对象的引用,就说明对象不是垃圾,如果一个对象没有任何引用指向它,那么改对象就是垃圾对象。

在对象头处维护一个counter,每增加一次对该对象的引用计数器自加,如果对该对象的引用失联,则计数器自减。当counter为0时,表明该对象已经被废弃,不处于存活状态。这种方式一方面无法区分软、虛、弱、强引用类别。另一方面,会造成死锁,假设两个对象相互引用始终无法释放counter,永远不能GC

弊端:如果一个对象A持有对象B,而对象B也持有一个对象A,那发生了类似操作系统中死锁的循环持有,这种情况下A与B的counter恒大于1,会使得GC永远无法回收这两个对象 。

可达性分析

通过一系列为GC Roots的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时,则证明该对象是不可用的。如果对象在进行可行性分析后发现没有与GC Roots相连的引用链,也不会理解死亡。它会暂时被标记上并且进行一次筛选,筛选的条件是是否与必要执行finalize()方法。如果被判定有必要执行finaliza()方法,就会进入F-Queue队列中,并有一个虚拟机自动建立的、低优先级的线程去执行它。稍后GC将对F-Queue中的对象进行第二次小规模标记。如果这时还是没有新的关联出现,那基本上就真的被回收了。

那么那些点可以作为GC Roots呢?一般来说,如下情况的对象可以作为GC Roots

  1. 虚拟机栈(栈桢中的本地变量表)中的引用的对象
  2. 方法区中的类静态属性引用的对象
  3. 方法区中的常量引用的对象
  4. 本地方法栈中JNI(Native方法)的引用的对象

对于大多数人来说主要是理解上面这四点。要通过这四点去反推,去领悟为什么能把他们当做GC Roots。把四点理解清楚了,理解的这GC Roots就简单了。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-04-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java后端技术栈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 对象的生命周期
    • 创建阶段
      • 应用阶段
        • 可以见阶段
          • 不可达阶段
            • 收集阶段
              • 终结阶段
                • 对象空间又一次分配阶段
                • Java对象的四大引用
                  • 强引用
                    • 弱引用
                      • 软引用
                        • 虚引用
                        • 如何确定一个对象是垃圾对象?
                          • 引用计数法
                            • 可达性分析
                            领券
                            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档