专栏首页程序猿杂货铺什么样的对象需要被 GC ?

什么样的对象需要被 GC ?

阅读文本大概需要 5 分钟。

引言

上一篇文章 JVM 基本介绍 我们了解了一些基本的 JVM 知识,本篇开始逐步学习垃圾回收,我们都知道既然叫垃圾回收,那回收的就应该是垃圾,可是我们怎么知道哪些对象是垃圾呢? 哪些对象需要被回收? 什么时候需要回收呢?

判断算法

引用计数算法

给每个对象设置一个计数器,每当该对象被引用时引用计数器加 1,有引用断开时引用计数减 1。当引用计数为 0 时表示该对象可以被回收。

这个可以用数据算法中的图形表示,对象 A-对象 B-对象 C 都有引用,所以不会被回收,对象 B 由于没有被引用,没有路径可以达到对象 B,对象 B 的引用计数就就是 0,对象 B 就会被回收。

优点

客观地说,引用计数算法的实现简单,判定效率也很高,在大部分情况下它都是一个不错的算法,也有一些比较著名的应用案例,例如微软公司的 COM(Component Object Model)技术、使用 ActionScript 3 的 FlashPlayer、Python 语言和在游戏脚本领域被广泛应用的 Squirrel 中都使用了引用计数算法进行内存管理。

缺点

主流的 Java 虚拟机里面没有选用引用计数算法来管理内存,其中最主要的原因是它很难解决对象之间相互循环引用的问题。因为相互引用,计数器值永远也不会成为 0 ,所以永远达不到被 GC 回收的条件。

例如下图:对象A,对象B 循环引用,没有其他的对象引用A和B,则A和B 都不会被回收。

可达性分析算法

该算法的原理是:以 GCRoots 的对象作为起始点,然后以该节点为基准开始向下搜索,搜索过程中搜索路径我们称之为引用链,当一个对象到 GCRoots 没有任何引用链连接的时候,说明该对象是不可用的。

注意:我们在 上边的所说的引用都是指定的强引用关系

因为我们知道 Java 中存在四种引用对象,根据引用强度(从上至下依次减弱)可依次划分为:

  • 强引用 StrongReference
  • 软引用 WeakReference
  • 弱引用 PhantomReference
  • 虚引用 SoftReference

详细的概念大家下去可以自行查看,此处不再赘述。

可以用作 GC Roots 的对象
  • 方法区 : 类静态变量引用的对象
  • 方法区 : 常量引用的对象
  • 虚拟机栈 : 本地变量表中引用的对象
  • 本地方法栈 : JNI (带 Native 关键字)引用的对象

如下图,对象 D 和根对象之间毫无引用链,则会被回收。

由于这种算法即使存在互相引用的对象,但如果这两个对象无法访问到根对象,还是会被回收。如下图:对象 C 和对象 D 互相引用,但是由于无法访问根节点,还是会被回收。

不可达是不是就一定会被回收?

答案是不一定

一个对象在真正被回收之前,需要经历两次标记过程:

第一次标记

如果对象在进行可达性分析之后发现没有与 GC Roots 相连接的引用链,那它将会被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行 finalize() 方法,此时分两种情况:

  • 对象没有覆盖 finalize() 方法
  • finalize() 方法已经被虚拟机调用过

在这两种情况下虚拟机都认为此时没有必要执行垃圾回收。

第二次标记

在第一次标记判定基础之上,如果判定为有必要执行 finalize() 方法,则虚拟机会把这个对象放置到一个叫做 F-Queue 的队列之中,并在之后用 Finalizer 线程去执行回收。(此处的执行指的是 虚拟机会去触发这个方法,但是并不保证回收成功,也不承诺会等待他运行结束,因为如果有个别对象在 finalize() 方法中执行缓慢甚至发生死循环的时候,有可能会导致 F-Queue 队列中的其他对象发生永久等待,最后导致整个垃圾回收系统崩溃)

总结

  • 引用计数法:简单高效,但是对于相互循环引用的对象无法判断是否应该被回收
  • 可达性分析:目前大多虚拟机厂商采用的垃圾回收算法,通过判断其他对象是否和根节点之间存在引用链来分析是否应该被回收
  • 不可达的对象不一定会立即被回收

本文分享自微信公众号 - 程序猿杂货铺(zhoudl_l),作者:zhoudl

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-03-14

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 通过软引用和弱引用提升JVM内存使用性能的方法(面试时找机会说出,一定能提升成功率)

    指向通过new得到的内存空间的引用叫强引用。比如有String a = newString("123");,其中的a就是一个强引用,它指向了一块内容是123的堆...

    周三不加班
  • 【LeetCode - 018】四数之和

    Given an array S of n integers, are there elements a, b, c, and d in S such that...

    周三不加班
  • 数据库大批量 SQL 插入性能优化

    修改后的插入操作能够提高程序的插入效率。这里第二种 SQL 执行效率高的主要原因是合并后日志量(MySQL 的binlog 和 innodb 的事务让日志)减少...

    周三不加班
  • 垃圾回收器如何处理循环引用

    垃圾回收是一门编程语言中必不可少的一部分,不论是手动释放内存的C和C++,还是自动回收垃圾的Java和C#等语言。对于Java这样的语言,一般的开发者不强求关心...

    技术小黑屋
  • Java强引用、软引用、弱引用及虚引用深入探讨

    引用类型在日常开发中并不常关注,也很少注意到,因此很多人忽略了它们的存在,而事实上,引用类型在Java体系中扮演着十分重要的角色,要想对Java体系有一个更深层...

    弗兰克的猫
  • Java对象引用四个级别(强、软、弱、虚)

    最近,高级Java技术栈微信群中,有一些猿友在讨论JVM中对象的周期问题,有谈到引用的级别,现在为大家做个总结吧,虽然大多数公司并没有意识或者用到这些引用,但了...

    Java技术栈
  • Java Review (十八、面向对象----对象与垃圾回收)

    Java 内存运行时区域中的程序计数器、虚拟机栈、本地方法栈随线程而生灭;因此这几个区域的内存分配和回收都具备确定性,不需要过多考虑回收的问题,因为方法结束或者...

    三分恶
  • JVM学习记录-对象已死吗

    前言 先来回顾一下,在jvm运行时数据区,分为两部分,一个部分是线程共享区,主要包括堆和方法区,另一部是线程私有区分包括本地方法栈,虚拟机栈和程序计数器。在线程...

    纪莫
  • JVM&GC之java引用

    Java中的引用有点像C++中的指针,通过引用可以对堆中的对象进行操作。在Java程序中最常见的引用类型是强引用,也是默认的引用类型。当在Java语言中使用Ne...

    一觉睡到小时候
  • AS3 内存回收机制

           AS3相对于以前版本的功能增强了很多,在赋予它重任时,同时也要它付出代价:垃圾收集器不再支持自动为你收集垃圾。本文中,我为大家整理了一些资料。首先...

    py3study

扫码关注云+社区

领取腾讯云代金券