gc流程和选择

本文介绍了垃圾收集的概念,包括引用计数和根可达算法。详细讲解了不同的GC清除方法,如Mark-Sweep和Copying算法,以及GC模型,如Serial、Parallel Scavenge和CMS。讨论了CMS的并发标记、重新标记和并发清理阶段,强调了减少STW时间的重要性。最后,文章涵盖了JVM调优,旨在减少老年代Full GC次数,提高系统吞吐量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

什么是垃圾?Garbage Collectors

没有引用指向的就是要回收的垃圾

一旦引用失效或不存在 就会memory leak内存泄漏 达到一个极端 就会 oom内存溢出

在这里插入图片描述

1.引用计数

判断是否是要回收的垃圾

在这里插入图片描述

环形垃圾就不能用引用计数判断

在这里插入图片描述

2.Root Searching 根可达算法

判断是否是垃圾

根据主线程一直达到端点

清除方法

1.Mark-Sweep 标记后清除

就会 内存碎片化

在这里插入图片描述

一旦整体的大对象来了就会把存活的对象的挤出去 导致 oom内存溢出

2.copying拷贝算法

把内存空间划分一半出来 只有上半部分可以存对象,把存活的对象拷贝到另一边删除上半部分的全部对象就不会 内存碎片化

在这里插入图片描述

3.Mark-Compact标记垃圾和不是垃圾的都

Mark-Sweep是用空间换时间Mark-Compact则是用时间换空间。Mark阶段用来发现并标记所有活的对象,然后compact阶段才移动对象来达到Compact的目的。如果Compact方式是Sliding Compaction,则在Mark之后就可以按顺序一个个对象“滑动”到空间的某一侧进行内存划分这样就不会 内存碎片化,同时压缩阶段是会暂停应用的,所以给我们应该尽量避免对象出现在老年代。

标出来进行压缩清理 效率低

在这里插入图片描述

Gc模型

在这里插入图片描述

前6种为分代模型,后三种是分区模型

Serial与Serial-old

stw停止业务线程由一个线程进行回收 Serial-old也是一样的只是工作在老年代,一般是几十mb

在这里插入图片描述

Parallel Scavenge与Parallel Scavengel-old

stw停止业务线程由多个线程进行回收 Parallel Scavengel-old也是一样的只是工作在老年代

在这里插入图片描述

cms

stw stop-the-world 停止业务线程

concurrent mark sweep并发 low-pause短的stw 的 collector回收器

内存空间越来越大,上面的策略不能处理,就是当stw的时间越来越长非常长;

cms就是缩短stw时间,业务线程停止的时间减短也就是垃圾回收线程缩短,响应也就及时

特点
  • 初始标记(initial mark) 有 STW

  • 并发标记(concurrent mark) 没有 STW在这里插入图片描述

  • 重新标记(remark) 有 STW

  • 并发清除(concurrent sweep) 没有 STW

黄色是垃圾回收

初始标记

在垃圾回收线程并发标记工作时并不停止业务线程,

并发标记的两种情况

浮动垃圾:在并发标记阶段产生了新垃圾不会被及时回收,而是只能等到下一次GC

floating garbage -留到下次清除

在这里插入图片描述

重新标记(重点)

就是为了修正错标的问题

重新标记:为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录。

重新标记,重新从GC Root开始查找新关联的对象,并进行标记;而初始标记、并行标记两个步骤标记的对象,即使并行标记过程中已经没有相关引用了,也不会再去清除这些对象的标记(直到等到下一次GC发生的时候再去清除)

并发清理

通过以上阶段的标记,老年代所有存活的对象已经被标记并且现在要通过Garbage Collector采用清扫的方式回收那些不能用的对象了。
这个阶段主要是清除那些没有标记的对象并且回收空间;

由于CMS并发清理阶段用户线程还在运行着,伴随程序运行自然就还会有新的垃圾不断产生,这一部分垃圾出现在标记过程之后,CMS无法在当次收集中处理掉它们,只好留待下一次GC时再清理掉。这一部分垃圾就称为“浮动垃圾”。

分代模型和分区模型

不管内存大小 都是先分代模型判断够不够,不够就选择分区模型

分代一般2个gc,分区1个gc

分区模型是分成很多小块,分时间段管理其中几块,然后下个时间段再管其中几块

在这里插入图片描述

堆内存逻辑分区 分代模式

如何从新生代到老年代?

先是eden没被回收的就升一次级升级到特定等级就存入老年代。

第一个survivor就是Fromspace 第二个survivor就是Tospace

第一次新生代的eden创建 new了10个对象 ,如果只有1个保存就用copying算法把活的对象存入fromspace,清掉eden;第二次eden又创建 new了10个对象,如果只有1个保存就用copying算法把活的对象存入Tospace,并且把fromspace的那一个也存入Tospace,清掉eden和fromspace,第三次eden又创建 new了10个对象,如果只有1个保存就用copying算法把活的对象存入fromspace,又把tospace的两个存入fromspace; fromspace和tospace来去往返的切换copying算法存储

eden满了survivor满了就存入老年代

在这里插入图片描述

栈逃逸

先在栈上分配,内存够用就存入栈, 栈中的方法引用结束,就pop弹出栈引用,栈针就下移一位,直接结束,不用垃圾回收器介入,占的内存很少。

栈的a对象在方法内部分配里面有局部对象;但是另一个b方法对象用了a的局部对象,就不能在栈中分配,会发生栈逃逸,就要去堆
在这里插入图片描述

FGC FullGC全量回收

TLAB thread local allocation buffer 线程本地分配缓存区, 会发生线程之间的竞争,为了去除线程之间的竞争,就设计了线程私有本地空间

在这里插入图片描述

jvm调优

减少老年代的fullgc次数(减少stop the world次数)增大老年代内存

吞吐量 程序运行5个小时 只有2个小时在运行 其余时间都是老年代full时的stop the world,gc调优就在于减少stop the world次数

ART(Garbage Collection,垃圾收集)是指一种内存管理技术,用于自动检测并释放不再使用的程序内存空间,避免内存泄露内存溢出。在Java中,垃圾收集主要是由JVM(Java Virtual Machine)负责的,不是直接在应用代码中显式控制的。 在Java代码层面,我们通常不会直接编写GC相关的代码,因为这通常是运行时环境的任务。然而,在某些高级特性如Finalizer、WeakReference、SoftReference等场景下,开发者可能会间接影响GC的行为。例如: ```java // 使用软引用示例 SoftReference softRef = new SoftReference(new Object()); // 当系统内存紧张时,softRef指向的对象会被回收 ``` 至于ART GC流程,虽然Java不公开详细的底层源码,但大体上包括以下几个阶段: 1. **标记**(Marking):找出所有可达的对象(可达即存在引用链) 2. **扫描**(Scanning):遍历未被标记的对象区域 3. **压缩**(Compacting):移动已标记对象到堆的特定区域,腾出空间供未来分配 对于GC流程图,这是一个简化版本的概念图,展示的是典型分代GC模型(如新生代、老年代)的工作流程: - 新生代:年轻代分为Eden区、Survivor区,经历复制(Copy)、 Minor GC; - 老年代:对象存活时间长,经历Minor GC后移至老年代,达到年龄阈值或大小阈值则触发Major GC; - 全局GC:Major GC后进行Full GC,对整个堆进行整理。 如果你需要了解具体的ART GC算法细节,建议查阅官方文档或深入研究JVM的源码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值