GC是如何判断一个对象为垃圾的?被GC判断为垃圾的对象一定会被回收吗?

article/2025/9/19 14:23:31

一.GC如何判断一个对象为”垃圾”的

java堆内存中存放着几乎所有的对象实例,垃圾收集器在对堆进行回收前,第一件事情就是要确定这些对象之中哪些还“存活”着,哪些已经“死去”。那么GC具体通过什么手段来判断一个对象已经”死去”的?

1.引用计数算法(已被淘汰的算法)

给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的。

目前主流的java虚拟机都摒弃掉了这种算法,最主要的原因是它很难解决对象
之间相互循环引用的问题。尽管该算法执行效率很高。

2.可达性分析算法

目前主流的编程语言(java,C#等)的主流实现中,都是称通过可达性分析(Reachability Analysis)来判定对象是否存活的。这个算法的基本思路就是通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连(用图论的话来说,就是从GC Roots到这个对象不可达)时,则证明此对象是不可用的。如下图所示,对象object 5、object 6、object 7虽然互相有关联,但是它们到GC Roots是不可达的,所以它们将会被判定为是可回收的对象。

这里写图片描述

在Java语言中,可作为GC Roots的对象包括下面几种:

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象。
  • 方法区中类静态属性引用的对象。
  • 方法区中常量引用的对象。
  • 本地方法栈中JNI(即一般说的Native方法)引用的对象。

二.被GC判断为”垃圾”的对象一定会回收吗

即使在可达性分析算法中不可达的对象,也并非是“非死不可”的,这时候它们暂时处于“缓刑”阶段,要真正宣告一个对象死亡,至少要经历两次标记过程:如果对象在进行可达性分析后发现没有与GC Roots相连接的引用链,那它将会被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,虚拟机将这两种情况都视为“没有必要执行”。(即意味着直接回收)

如果这个对象被判定为有必要执行finalize()方法,那么这个对象将会放置在一个叫做F-Queue的队列之中,并在稍后由一个由虚拟机自动建立的、低优先级的Finalizer线程去执行它。这里所谓的“执行”是指虚拟机会触发这个方法,但并不承诺会等待它运行结束,这样做的原因是,如果一个对象在finalize()方法中执行缓慢,或者发生了死循环(更极端的情况),将很可能会导致F-Queue队列中其他对象永久处于等待,甚至导致整个内存回收系统崩溃。

finalize()方法是对象逃脱死亡命运的最后一次机会,稍后GC将对F-Queue中的对象进行第二次小规模的标记,如果对象要在finalize()中成功拯救自己——只要重新与引用链上的任何一个对象建立关联即可,譬如把自己(this关键字)赋值给某个类变量或者对象的成员变量,那在第二次标记时它将被移除出“即将回收”的集合;如果对象这时候还没有逃脱,那基本上它就真的被回收了。

代码示例:

public class FinalizeEscapeGC {public static FinalizeEscapeGC SAVE_HOOK = null;public void isAlive() {System.out.println("yes,i am still alive:)");}@Overrideprotected void finalize() throws Throwable {super.finalize();System.out.println("finalize mehtod executed!");FinalizeEscapeGC.SAVE_HOOK = this;}public static void main(String[] args) throws Throwable {SAVE_HOOK = new FinalizeEscapeGC();// 对象第一次成功拯救自己SAVE_HOOK = null;System.gc();// 因为finalize方法优先级很低,所以暂停0.5秒以等待它Thread.sleep(500);if (SAVE_HOOK != null) {SAVE_HOOK.isAlive();} else {System.out.println("no,i am dead:(");}// 下面这段代码与上面的完全相同,但是这次自救却失败了SAVE_HOOK = null;System.gc();// 因为finalize方法优先级很低,所以暂停0.5秒以等待它Thread.sleep(500);if (SAVE_HOOK != null) {SAVE_HOOK.isAlive();} else {System.out.println("no,i am dead:(");}}
}

运行结果:

finalize mehtod executed!
yes,i am still alive:)
no,i am dead:(

SAVE_HOOK对象的finalize()方法确实被GC收集器触发过,并且在被收集前成功逃脱了。另外一个值得注意的地方是,代码中有两段完全一样的代码片段,执行结果却是一次逃脱成功,一次失败,这是因为任何一个对象的finalize()方法都只会被系统自动调用一次,如果对象面临下一次回收,它的finalize()方法不会被再次执行,因此第二段代码的自救行动失败了。因为finalize()方法已经被虚拟机调用过,虚拟机都视为“没有必要执行”。(即意味着直接回收)

《深入理解java虚拟机 JVM高级特性与最佳实践》周志明


http://chatgpt.dhexx.cn/article/H4n41GST.shtml

相关文章

基于28181协议的视频与平台的对接

问题描述 将IPC摄像头接入平台进行观看,或使用28181/rtsp/rtmp/flv等协议将视频流分发到其他平台。 解决方案 WVP-PRO(基于GB/T 28181-2016标准实现的流媒体平台),依托优秀的开源流媒体服务ZLMediaKit,提供完善丰富…

GB28181协议实现系列之----SDK Demo发布(7)

GB28181在终端的应用越来越广,但是一般很多做终端的厂家要加入到互联互通的GB28181网络协议栈中都必须招聘一些专业做GB28181的开发人员,并且需要对接各厂家的兼容性开发及对接调试工作,或是修改一些定制功能。安防市场一年有千亿以上的产值&…

GB28181协议之设备录像查询

目录 一、概述 二、GB28181录像文件查询 2.1 录像文件基本要求 2.2 命令流程 2.3 抓包文件抓图示例 三、国标平台介绍 一、概述 近年来,国内视频监控应用发展迅猛,系统接入规模不断扩大,涌现了大量平台提供商,平台提供商的接…

ZLMediaKit+wvp-GB28181-pro,搭建28181协议视频平台

ZLMediaKitwvp-GB28181-pro,搭建28181协议视频平台 一,简介 ZLMediaKit:实现RTSP/RTMP/HLS/HTTP协议的轻量级流媒体框架,支持大并发连接请求 一个基于C11的高性能运营级流媒体服务框架,项目地址:ZLMediaKit 特点: 基…

java gb28181网关_视频网关GB28181协议转换解决方案

原标题:视频网关GB28181协议转换解决方案 应用需求及问题: 四川某一所学校,校园内装置有上百个摄像头,学校监控系统是RTSP协议,现在需求要把校园的监控系统视频画面接入到公安系统里, 可公安系统只支持GB-T…

GB28181协议--校时

1、简介 根据《GB/T 28181 —2016》7.10、9.10的要求,GB28181设备网络校时功能描述如下: 联网系统内的IP 网络服务器设备宜支持 NTP(见IETF RFC2030) 协议的网络统一校时服务。 网络校时设备分为时钟源和客户端, 支持客户/服务器的工作模式; 时钟源应支…

GB28181协议常见几种信令流程(一)

在监控系统中,常见的摄像机设备互联协议有国际标准的ONVIF、国标的GB28181和各厂商的私有连接协议,本章从GB28181-2016中摘抄整理常见信令流程,如28181的会话/媒体通道、SIP基本注册/注销流程、客户端主动发起视频点播流程、设备控制流程等。…

国标GB28181协议客户端开发(一)整体流程和技术选型

国标GB28181协议客户端开发(一)整体流程和技术选型 本系列文章将介绍国标GB28181协议设备端的开发过程。本文旨在探讨整体设计和技术选型方面的考虑,为开发人员提供指导和参考。文章将从设备端开发的整体架构、信令交互流程以及关键技术选型等…

java gb28181网关_国标GB28181协议对接网关

国标GB28181网关概述 国标GB28181《安全防范视频监控联网系统信息传输、交换、控制技术要求》最新版为2016年版,较2011年版更加完善,其是基于SIP协议的视频联网框架标准。因其核心应用于公安视频联网,在平安城市、雪亮工程超大规模视频监控联…

GB28181协议之录像回放

目录 一、概述 二、录像文件播放 2.1 基本要求 2.2 命令流程 2.3 抓包示例 2.3.1 Invite请求[SIP服务器---->设备] 2.3.2 Invite应答[设备---->SIP服务器] 2.3.3 ACK[SIP服务器---->设备] 2.3.4 Bye结束回放 2.3.5 Bye应答 2.3.6 播放速度控制 2.3.6 控制…

GB28181协议之实时视频

目录 一、概述 二、实时视频 2.1基本要求 2.2命令流程 2.3抓包示例 2.3.1 Invite请求[SIP服务器----->设备] 2.3.2 Invite应答[设备---->SIP服务器] 2.3.3 ACK[SIP服务器----->设备] 2.3.4 Bye 2.3.5 Bye应答 三、国标平台介绍 一、概述 近年来,国…

GB28181协议--实时视音频点播(预览)

1、基本要求 根据《GB/T 28181 —2016》第9章关于实时视音频点播的描述,其内容如下: 实时视音频点播的SIP 消息应通过本域或其他域的SIP 服务器进行路由、 转发, 目标设备的实时视音频流宜通过本域内的媒体服务器进行转发。实时视音频点播采用SIP 协议…

GB28181协议--心跳

1、心跳介绍: 根据《GBT 28181-2016 公共安全视频监控联网系统信息传输、交换、控制技术要求》9.6.1状态信息报送章节描述。 当源设备(包括网关、SIP 设备、SIP 客户端或联网系统) 发现工作异常时, 应立即向本 SIP 监控域的SIP服务器发送状态信息; 无异常时, 应定…

国标28181: 视频国标28181协议

国标的由来 GB28181国标解决平台与平台对接问题 比如A平台大连交警系统需要看B平台上海交警系统的视频。需要对接过来,实现调度视频。这时候需要知道他们取流的协议,各家厂商都自定义了一套协议,就很麻烦,因此国家就制定了GB28…

【C/C++】isalpha、islower、isupper、isalnum、isblank、isspace函数cctype / ctype.h头文件

isalpha、islower、isupper、isalnum、isblank、isspace这些函数都在<cctype>&#xff08;即C语言中的<ctype.h>&#xff09;的头文件里面&#xff0c;下图是它们所表示的范围&#xff1a; 总的来说就是&#xff1a; isalpha &#xff08;字母&#xff0c;包括大写…

细微之处见真章之StringUtils的isBlank函数细节解读

一、背景 技术群里有一个老铁分享了一段 commons-lang 的 StringUtils 工具类的代码&#xff1a; public static boolean isBlank(final CharSequence cs) {int strLen;if (cs null || (strLen cs.length()) 0) {return true;}for (int i 0; i < strLen; i) {if (Char…

字符串判空,isBlank 和 isEmpty 到底选那个?

字符串的判空&#xff0c;日常开发是经常要做的一种校验&#xff0c;common-lang包帮我们做了一些字符串判空的封装 <dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId> </dependency> 并对外提…

sbrk() 函数是干什么的?

brk和sbrk主要的工作是实现虚拟内存到内存的映射. 在GNU C中,内存分配是这样的: 每个进程可访问的虚拟内存空间为3G&#xff0c;但在程序编译时&#xff0c;不可能也没必要为程序分配这么大的空间&#xff0c;只分配并不大的数据段空间&#xff0c;程序中动态分配的空间就是从这…

ORACLE如何修改默认端口号

oracle在安装的的时候&#xff0c;除了可以默认端口号&#xff0c;也可以填入自定义的端口号。但是项目上会出现这样的情况&#xff0c;项目在进展时期&#xff0c;需要对数据库安全升级&#xff0c;首先要修改数据库的默认端口号。那如何来设置oracle的默认端口号&#xff0c;…

Oracle如何更改端口号

Oracle默认端口号为8080&#xff0c;因为Tomcat端口默认也是8080所以需要把Oracle端口更改一下&#xff0c;不建议更改Tomcat端口号 运行cmd命令行操作 查看Oracle版本&#xff1a; 链接Oracle数据库&#xff1a; conn system/root as sysdba&#xff0c;system/root用户名和…