jvm垃圾回收是什么时候触发的? 垃圾回收算法? 都有哪些垃圾回收器

article/2025/9/19 14:12:11

1.1。那究竟GC为我们做了什么操作呢?

 

1 哪些内存需要回收?    

2 什么时候回收?    

3 如何回收?    

 

这时候有人就会疑惑了,既然GC 已经为我们解决了这个矛盾,我们还需要学习GC 么?当然当然是肯定的,那究竟什么时候我们还需要用到的呢

 

1 排查内存溢出    

2 排查内存泄漏    

3 性能调优,排查并发瓶颈    

1.1.1。JVM怎么判断对象可以回收了?

我们知道,GC 主要处理的是对象的回收操作,那么什么时候会触发一个对象的回收的呢?

1,对象没有引用

2,作用域发生未捕获异常

3,程序在作用域正常执行完毕

4,程序执行了System.exit()

5,程序发生意外终止(被杀进程等)

其实,我们最容易想到的就是当对象没有引用的时候会将这个对象标记为可回收对象,那么现在就有一个问题,是不是这个对象被赋值为以后就一定被标记为可回收对象了呢

并不是这个对象被赋值为之后就一定被标记为可回收,有可能会发生逃逸!

 

1.2。下面我们来看一下几种垃圾收集算法

1.2.1。在JDK1.2之前,使用的是引用计数器算法,

即当这个类被加载到内存以后,就会产生方法区,堆栈,程序计数器等一系列信息,当创建对象的时候,为这个对象在堆栈空间中分配对象,同时会产生一个引用计数器,同时引用计数器1,当有新的引用的时候,引用计数器继续1,而当其中一个引用销毁的时候,引用计数器-1,当引用计数器被减为零的时候,标志着这个对象已经没有引用了,可以回收了!这种算法在JDK1.2之前的版本被广泛使用,但是随着业务的发展,很快出现了一个问题

当我们的代码出现下面的情形时,该算法将无法适应

a)ObjA.obj = ObjB

b)ObjB.obj - ObjA

                 这样的代码会产生如下引用情形 objA 指向objB ,而objB 又指向objA ,这样当其他所有的引用都消失了之后,objA objB 还有一个相互的引用,也就是说两个对象的引用计数器各为1 ,而实际上这两个对象都已经没有额外的引用,已经是垃圾了。


1.2.2。根搜索算法

                   根搜索算法是从离散数学中的图论引入的,程序把所有的引用关系看作一张图,从一个节点GC ROOT 开始,寻找对应的引用节点,找到这个节点以后,继续寻找这个节点的引用节点,当所有的引用节点寻找完毕之后,剩余的节点则被认为是没有被引用到的节点,即无用的节点。


目前java 中可作为GC Root 的对象有

1,虚拟机栈中引用的对象(本地变量表)

2,方法区中静态属性引用的对象

3,方法区中常量引用的对象

4,本地方法栈中引用的对象(Native Object)

 

1.2.3。        引用的分类

1,强引用

只要引用存在,垃圾回收器永远不会回收

Objectobj = new Object();

// 可直接通过物镜取得对应的对象obj.equels(NEWOBJECT()); 

而这样 obj对象对后面newObject的一个强引用,只有当obj这个引用被释放之后,对象才会被释放掉,这也是我们经常所用到的编码形式。

2、  软引用

非必须引用,内存溢出之前进行回收,可以通过以下代码实现

Objectobj = new Object();

SoftReference<Object>sf = new SoftReference<Object>(obj);

obj =null;

sf.get();//有时候会返回null

这时候sf是对obj的一个软引用,通过sf.get()方法可以取到这个对象,当然,当这个对象被标记为需要回收的对象时,则返回null
软引用主要用户实现类似缓存的功能,在内存足够的情况下直接通过软引用取值,无需从繁忙的真实来源查询数据,提升速度;当内存不足时,自动删除这部分缓存数据,从真正的来源查询这些数据。

3、  弱引用

第二次垃圾回收时回收,可以通过如下代码实现

Objectobj = new Object();

WeakReference<Object>wf = new WeakReference<Object>(obj);

obj =null;

wf.get();//有时候会返回null

wf.isEnQueued();//返回是否被垃圾回收器标记为即将回收的垃圾

弱引用是在第二次垃圾回收时回收,短时间内通过弱引用取对应的数据,可以取到,当执行过第二次垃圾回收时,将返回null

弱引用主要用于监控对象是否已经被垃圾回收器标记为即将回收的垃圾,可以通过弱引用的isEnQueued方法返回对象是否被垃圾回收器

4、  虚引用(幽灵/幻影引用)

           垃圾回收时回收,无法通过引用取到对象值,可以通过如下代码实现

Objectobj = new Object();

PhantomReference<Object>pf = new PhantomReference<Object>(obj);

obj=null;

pf.get();//永远返回null

pf.isEnQueued();//返回从内存中已经删除

虚引用是每次垃圾回收的时候都会被回收,通过虚引用的get方法永远获取到的数据为null,因此也被成为幽灵引用。

虚引用主要用于检测对象是否已经从内存中删除。

1.3.         方法区也是会被回收的

!但是方法区的回收条件非常苛刻,只有同时满足以下三个条件才会被回收!

1、所有实例被回收

2、加载该类的ClassLoader被回收

3Class对象无法通过任何途径访问(包括反射)

好了,我们现在切入正题,Java1.2之前主要通过引用计数器来标记是否需要垃圾回收,而1.2之后都使用根搜索算法来收集垃圾,而收集后的垃圾是通过什么算法来回收的呢?

1、    标记-清除算法

2、    复制算法

复制算法采用从根集合扫描,并将存活对象复制到一块新的,没有使用过的空间中,这种算法当控件存活的对象比较少时,极为高效,但是带来的成本是需要一块内存交换空间用于进行对象的移动。也就是我们前面提到的

s0 s1等空间。


3、    标记-整理算法

我们来逐一过一下

1、    标记-清除算法

        

标记-清除算法采用从根集合进行扫描,对存活的对象对象标记,标记完毕后,再扫描整个空间中未被标记的对象,进行回收,如上图所示。

标记-清除算法不需要进行对象的移动,并且仅对不存活的对象进行处理,在存活对象比较多的情况下极为高效,但由于标记-清除算法直接回收不存活的对象,因此会造成内存碎片!

2、    复制算法 


 复制算法采用从根集合扫描,并将存活对象复制到一块新的,没有使用过的空间中,这种算法当控件存活的对象比较少时,极为高效,但是带来的成本是需要一块内存交换空间用于进行对象的移动。也就是我们前面提到的

s0 s1等空间。

3、    标记-整理算法


 标记

-整理算法采用标记-清除算法一样的方式进行对象的标记,但在清除时不同,在回收不存活的对象占用的空间后,会将所有的存活对象往左端空闲空间移动,并更新对应的指针。标记-整理算法是在标记-清除算法的基础上,又进行了对象的移动,因此成本更高,但是却解决了内存碎片的问题。

我们知道,JVM为了优化内存的回收,进行了分代回收的方式,对于新生代内存的回收(minor GC)主要采用复制算法,下图展示了minor GC的执行过程。

1.4.          下面我们来逐一介绍一下每个垃圾回收器。

1.4.1.    1、    Serial收集器

看名字我们都可以看的出来,这个属于串行收集器。其运行示意图如下


 Serial

收集器是历史最悠久的一个回收器,JDK1.3之前广泛使用这个收集器,目前也是ClientVM ServerVM 44GB以下机器的默认垃圾回收器。串行收集器并不是只能使用一个CPU进行收集,而是当JVM需要进行垃圾回收的时候,需要中断所有的用户线程,知道它回收结束为止,因此又号称“Stop The World 的垃圾回收器。注意,JVM中文名称为java虚拟机,因此它就像一台虚拟的电脑一样在工作,而其中的每一个线程就被认为是JVM的一个处理器,因此大家看到图中的CPU0CPU1实际为用户的线程,而不是真正机器的CPU,大家不要误解哦。

 

串行回收方式适合低端机器,是Client模式下的默认收集器,对CPU和内存的消耗不高,适合用户交互比较少,后台任务较多的系统。

Serial收集器默认新旧生代的回收器搭配为Serial+SerialOld

1.4.2.    2、    ParNew收集器

ParNew收集器其实就是多线程版本的Serial收集器,其运行示意图如下

 

 同样有

Stop The World的问题,他是多CPU模式下的首选回收器(该回收器在单CPU的环境下回收效率远远低于Serial收集器,所以一定要注意场景哦),也是Server模式下的默认收集器。

 

1.4.3.    3、    ParallelScavenge

ParallelScavenge又被称为是吞吐量优先的收集器,器运行示意图如下

 


 ParallelScavenge

所提到的吞吐量=程序运行时间/(JVM执行回收的时间+程序运行时间),假设程序运行了100分钟,JVM的垃圾回收占用1分钟,那么吞吐量就是99%。在当今网络告诉发达的今天,良好的响应速度是提升用户体验的一个重要指标,多核并行云计算的发展要求程序尽可能的使用CPU和内存资源,尽快的计算出最终结果,因此在交互不多的云端,比较适合使用该回收器。

 

1.4.4.    4、    ParallelOld

ParallelOld是老生代并行收集器的一种,使用标记整理算法、是老生代吞吐量优先的一个收集器。这个收集器是JDK1.6之后刚引入的一款收集器,我们看之前那个图之间的关联关系可以看到,早期没有ParallelOld之前,吞吐量优先的收集器老生代只能使用串行回收收集器,大大的拖累了吞吐量优先的性能,自从JDK1.6之后,才能真正做到较高效率的吞吐量优先。其运行示意图如下

 


1.4.5.     5、   SerialOld

 

SerialOld是旧生代Client模式下的默认收集器,单线程执行;在JDK1.6之前也是ParallelScvenge回收新生代模式下旧生代的默认收集器,同时也是并发收集器CMS回收失败后的备用收集器。其运行示意图如下

 



 

1.4.6.        6、CMS

CMS又称响应时间优先(最短回收停顿)的回收器,使用并发模式回收垃圾,使用标记-清除算法,CMSCPU是非常敏感的,它的回收线程数=CPU+3/4,因此当CPU2核的实惠,回收线程将占用的CPU资源的50%,而当CPU核心数为4时仅占用25%。他的运行示意图如下

 


 CMS

模式主要分为4个过程


 在初始标记的时候,需要中断所有用户线程,在并发标记阶段,用户线程和标记线程

并发执行,而在这个过程中,随着内存引用关系的变化,可能会发生原来标记的对象被释放,进而引发新的垃圾,因此可能会产生一系列的浮动垃圾,不能被回收。

 

CMS 为了确保能够扫描到所有的对象,避免在InitialMarking 中还有未标识到的对象,采用的方法为找到标记了的对象,并将这些对象放入Stack 中,扫描时寻找此对象依赖的对象,如果依赖的对象的地址在其之前,则将此对象进行标记,并同时放入Stack 中,如依赖的对象地址在其之后,则仅标记该对象。

在进行ConcurrentMarking minor GC 也可能会同时进行,这个时候很容易造成旧生代对象引用关系改变,CMS 为了应对这样的并发现象,提供了一个Mod UnionTable 来进行记录,在这个Mod Union Table中记录每次minor GC 后修改了的Card 的信息。这也是ParallelScavenge不能和CMS一起使用的原因。

CMS产生浮动垃圾的情况请见如下示意图

 

在运行回收过后,c就变成了浮动垃圾。

由于CMS会产生浮动垃圾,当回收过后,浮动垃圾如果产生过多,同时因为使用标记-清除算法会产生碎片,可能会导致回收过后的连续空间仍然不能容纳新生代移动过来或者新创建的大资源,因此会导致CMS回收失败,进而触发另外一次FULL GC,而这时候则采用SerialOld进行二次回收。

同时CMS因为可能产生浮动垃圾,而CMS在执行回收的同时新生代也有可能在进行回收操作,为了保证旧生代能够存放新生代转移过来的数据,CMS在旧生代内存到达全部容量的68%就触发了CMS的回收!

1.4.7.    7、    GarbageFirst(G1 )

我们再来看垃圾回收器的总图,刚才我们可以看到,我在图上标记了一个?,其实这是一个新的垃圾回收器,既可以回收新生代也可以回收旧生代,SunHotSpot1.6u14以上EarlyAccess版本加入了这个回收器,sun公司预期SunHotSpot1.7发布正式版,他是商用高性能垃圾回收器,通过重新划分内存区域,整合优化CMS,同时注重吞吐量和响应时间,但是杯具的是被oracle收购之后这个收集器属于商用收费收集器,因此目前基本上没有人使用,我们在这里也就不多介绍,更多信息可以参考oracle新版本JDK说明。

下面我们再来看下JVM的一些内存分配与回收策略

1、    优先在Edon上分配对象

 


 对于新生代和旧生代,

JVM可使用很多种垃圾回收器进行垃圾回收,下图展示了不同生代不通垃圾回收器,其中两个回收器之间有连线表示这两个回收器可以同时使用。
 

 而这些垃圾回收器又分为串行回收方式、并行回收方式合并发回收方式执行,分别运用于不同的场景。如下图所示

 

2    大对象直接进入老生代

3、    年长者(长期存活对象)进入老生代

4、    群体效应(大批中年对象进入老生代)

5、    担保GC(担保minorGC)

担保GC 就是担保minorGC 能够满足当前的存储空间,而无需触发老生代的回收,由于大部分对象都是朝生夕死的,因此,在实际开发中这种很起效,但是也有可能会发生担保失败的情况,当担保失败的时候会触发FullGC ,但是失败毕竟是少数,因此这种一般是很划算的
  


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

相关文章

Java回收垃圾的基本过程与常用算法

目录 一、基本概述 二、垃圾分类 基本背景 举例说明各种引用类型的作用 强引用&#xff08;Strong Reference&#xff09; 软引用&#xff08;Soft Reference&#xff09; 弱引用&#xff08;Weak Reference&#xff09; 虚引用&#xff08;Phantom Reference&#xff…

java面试-GC垃圾回收机制

原理&#xff1a; GC是垃圾收集的意思&#xff08;Garbage Collection&#xff09;,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的。 简而言之&#xff0c;GC是将java的无用的堆对象进行清理&#xff0c;释放内存&#xff0c;以免发生内存泄露。…

JVM垃圾回收算法、GC和分代回收、三色标记并发漏标、垃圾回收器

一.标记清除 标记速度与存活对象线性关系 清除速度与内存大小线性关系 标记清除法分为标记阶段和清除阶段&#xff0c;标记阶段首先找到一些GC Root对象&#xff08;根对象&#xff09;&#xff0c;根对象是那些一定不能被回收的对象。清除阶段比较简单&#xff0c;加标记的对…

垃圾回收的主要区域是堆,那方法区会回收吗?

有些人认为方法区&#xff08;如HotSpot虚拟机中的元空间或者永久代&#xff09;是没有垃圾收集行为的&#xff0c;《Java虚拟机规范》中提到过可以不要求虚拟机在方法区中实现垃圾收集&#xff0c;事实上也确实有未实现或未能完整实现方法区类型卸载的收集器存在&#xff08;如…

GC(垃圾回收)详解

JVM 1.年轻代&#xff1a;年轻代主要存放新创建的对象&#xff0c;垃圾回收会比较频繁。(稍微讲细一点就是即可&#xff0c;年轻代分成Eden Space和Suvivor Space。当对象在堆创建时&#xff0c;将进入年轻代的Eden Space。垃圾回收器进行垃圾回收时&#xff0c;扫描Eden Spac…

java---垃圾回收算法(GC)

目录 一、如何判断一个对象是否存活 1.引用计数法 2.可达性分析法 二、垃圾回收算法 1.标记清除法 2.复制算法 3.标记整理法 4.分代算法 具体流程 注意事项 空间分配担保原则 总结 一、如何判断一个对象是否存活 Java 堆中存放着几乎所有的对象实例&#xff0c;垃圾…

Java - GC 垃圾回收

JVM中一个垃圾回收线程&#xff0c;它的优先级较低&#xff0c;正常情况下不会执行。JVM空闲或者当前内存不足时,才会触发垃圾回收线程执行,扫描内没有被引用的对象,将这些对象添加到要回收的集合中进行回收。 GC介绍 Garbage Collection 垃圾收集&#xff0c;监测对象是否可…

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

一.GC如何判断一个对象为”垃圾”的 java堆内存中存放着几乎所有的对象实例&#xff0c;垃圾收集器在对堆进行回收前,第一件事情就是要确定这些对象之中哪些还“存活”着,哪些已经“死去”。那么GC具体通过什么手段来判断一个对象已经”死去”的&#xff1f; 1.引用计数算法(…

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

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

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

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

GB28181协议之设备录像查询

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

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

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

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

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

GB28181协议--校时

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

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

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

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

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

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

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

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应答 三、国标平台介绍 一、概述 近年来&#xff0c;国…

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

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