垃圾回收器和内存分配

news2025/2/1 9:54:35

垃圾回收器和内存分配策略

概述
垃圾回收(Garbage Collection)简称GC,早在Lisp还在胚胎时期时,其作者John McCarthy就思考过垃圾回收需要完成的三件事情:

哪些内存需要回收

什么时候回收

如何回收

今天的内存动态分配与内存回收机制已经非常成熟了,都进入了“自动化时代”,那我们为什么还要学习垃圾回收和内存分配呢?

当我们需要检查各种内存溢出,内存泄漏问题时,当垃圾收集成为系统达到更高并发量的瓶颈时,我们就需要对这些“自动化”的技术进行监控和调节

1.如何判断对象可以回收

1.1 引用计数法

img

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

优点:原理简单,判定效率高

缺点:需要占用一定额外的内存空间,需要考虑大量的额外情况,在java虚拟机中没有采用这种方式来判断对象是否能够回收

1.2 可达性分析算法

img

通过“GC Roots”的根对象作为起始节点集,从这些节点根据关系引用开始往下搜索,搜索过程走过的路径称为“引用链”,如果摸个对象到GC Roots间没有任何引用链相连,,或者说不可达时,则证明此对象是可以被回收的

在Java体系内,固定可以作为GC Roots的对象包括:

1.在虚拟机栈(栈帧中的本地变量表)中引用的对象,譬如各个线程被调用的方法堆栈中使用到的 参数、局部变量、临时变量等。

2.在方法区中类静态属性引用的对象,譬如Java类的引用类型静态变量。 ·

3.在方法区中常量引用的对象,譬如字符串常量池(String Table)里的引用。

4.在本地方法栈中JNI(即通常所说的Native方法)引用的对象。

5.Java虚拟机内部的引用,如基本数据类型对应的Class对象,一些常驻的异常对象(比如 :NullPointExcepiton、OutOfMemoryError)等,还有系统类加载器。

6.所有被同步锁(synchronized关键字)持有的对象。

7.反映Java虚拟机内部情况的JM XBean、JVM TI中注册的回调、本地代码缓存等。

1.3 四种引用

  1. 强引用
    只有所有 GC Roots 对象都不通过【强引用】引用该对象,该对象才能被垃圾回收
  2. 软引用( SoftReference )
    仅有软引用引用该对象时,在垃圾回收后,内存仍不足时会再次出发垃圾回收,回收软引用
    对象
    可以配合引用队列来释放软引用自身
  3. 弱引用( WeakReference )
    仅有弱引用引用该对象时,在垃圾回收时,无论内存是否充足,都会回收弱引用对象
    可以配合引用队列来释放弱引用自身
  4. 虚引用( PhantomReference )
    必须配合引用队列使用,主要配合 ByteBuffer 使用,被引用对象回收时,会将虚引用入队,
    由 Reference Handler 线程调用虚引用相关方法释放直接内存
  5. 终结器引用( FinalReference )
    无需手动编码,但其内部配合引用队列使用,在垃圾回收时,终结器引用入队(被引用对象
    暂时没有被回收),再由 Finalizer 线程通过终结器引用找到被引用对象并调用它的 finalize
    方法,第二次 GC 时才能回收被引用对象

2.垃圾回收算法

2.1 标记清除算法(Mark-Sweep)

img

算法分为标记和清除两个阶段:

首先标记出所有需要进行回收的对象,在标记完成后,统一回收掉所有被标记的对象

**优点:**速度快

**缺点:**执行效率不稳定;容易造成内存碎片

2.2 标记整理(Mark Compact

img

先进行标记,让所有存活的对象向内存的一端移动,然后直接清理掉边界以外的内存

**优点:**不会产生内存碎片

**缺点:**由于涉及到了存活对象的移动,这种移动需要全程暂停应用程序才可以进行,这种停顿被作者称为“Stop The World”

**2.3 复制(**Copy

img

**优点:**不会有内存碎片

**缺点:**需要占用双倍内存空间

3. 分代垃圾回收

img

对象首先分配在伊甸园区域 新生代空间不足时,触发 minor gc ,伊甸园和 from 存活的对象使用 copy 复制到 to 中,存活的 对象年龄加 1 并且交换 from to
minor gc 会引发 stop the world ,暂停其它用户的线程,等垃圾回收结束,用户线程才恢复运行
当对象寿命超过阈值时,会晋升至老年代,最大寿命是 15 ( 4bit )
当老年代空间不足,会先尝试触发 minor gc ,如果之后空间仍不足,那么触发 full gc , STW 的时 间更长

3.1 相关 JVM 参数

img

4.垃圾收集器

概述

七款经典的垃圾收集器

串行收集器:Serial,Serial old

并行收集器:PawNew,Parallel Scavenge,Parallel Old

并发收集器:CMS,G1


新生代收集器:Serial,PawNew,Parallel Scavenge

老年代收集器:Serial old,Parallel Old,CMS

整堆收集器:G1

需要明确的是:虽然我们会对回收器进行比较,但并非为了挑选出一个最好的回收器,虽然垃圾收集器的技术在不断进步,但是还是没有出现最好的收集器,所以我们只是针对具体的场景应用最合适的收集器。

垃圾收集器的组合关系

img

4.1Serial收集器-串行回收

Serial收集器是最基础,历史最悠久的收集器,是一个单线程工作的收集器,这里的单线程不仅仅强调它只会使用一个处理器或者一条线程去完成垃圾回收的工作,更意味着它在进行垃圾收集的时候。必须暂停其他所有工作的线程才可以进行,称为“Stop The World”,对于交互较强的应用来说这种停顿是不可接收的

一个有趣的例子:“妈妈在打扫房间的时候肯定会让你老老实实呆着,如果她一边打扫你一边乱扔,这房间打扫的完?”是一个合情合理的矛盾

优点:简单而高效,运行在client模式下的虚拟机是个不错的选择

4.2PawNew收集器-并行回收

PawNew GC是Serial GC的多线程版本

PawNew收集器除了是采用并行收回的方式执行内存回收之外,其他与Serial GC几乎没有任何区别,都是采用了复制算法和“Stop The World”机制

PawNew是很多JVM运行在server模式下新生代默认的垃圾收集器

img

对于新生代,回收频率高,采用并行的方式高效

对于老年代,回收频率低,采用串行方式节省资源(省去切换线程的资源)

4.3Parallel收集器-吞吐量优先

Parallel ScavengeGC与PawNew GC不同,Parallel Scavenge收集器的目标是达到一个可控制的 吞吐量(Throughput),它也被称为吞吐量优先的一个垃圾收集器

自适应调节策略也是Parallel ScavengeGC与PawNew GC的一个重要区别

高吞吐量则可以高效的利用CPU的时间,尽快的完成计算任务,主要适合在后台运算而不需要太多交互的任务。例如,那些批量处理,订单处理,工资支付等

Parallel收集器在jdk6提供了用于执行老年代垃圾收集器Paralle Old,用来代替Serial Old

Paralle Old收集器采用了标记-压缩算法 但也还是基于并行回收和“Stop The World”机制

img

在吞吐量优先的场景下,Parallel+Parallel Old收集器的组合,在server模式下内存回收性能很不错

在java8中,默认是此垃圾回收器

4.4CMS收集器-低延迟

CMS收集器:HotSpot虚拟机第一个真正意义上的并发收集器,第一次实现了让垃圾收集线程和用户线程同时工作

注意:JDK9之后使用CMS垃圾收集器后,默认年轻代就为ParNew收集器,并且不可更改,同时JDK9之后被标记为不推荐使用,JDK14就被删除了。

CMS收集器收集器的关注点就是尽可能缩短垃圾收集时用户进程停顿的时间 停顿时间越短越适合与用户交互的程序,良好的响应速度能够提高用户的体验

CMS收集器采用标记-清除算法,并且也会“Stop The World”

CMS作为老年代的收集器,新声代只能选择PawNew和Serial,而不能和Parallel Scavenge组合使用

img

CMS工作过程

初始标记阶段:在这个阶段中,程序中所有的进程都会因为“Stop The World”机制而出现短暂的暂停,这个阶段的任务仅仅是标记和“GC Roots”能直接关联到的对象,由于关联对象较小,所以这里速度较快

并发标记阶段:从“GC Roots”的直接关联对象开始遍历整个对象图的过程,这个比较耗时但不需要停顿用户线程,可以和其他垃圾收集线程一起并发运行

重新标记阶段:由于并发标记阶段,程序的工作线程会和垃圾回收线程交叉运行,因为为了修正并发标记期间,因用户程序继续运作而导致标记产生变化的那一部分对象的标记记录

并发清除阶段:此阶段删除掉那些在标记阶段判断已经死亡的对象,释放内存空间

img

那既然标记-清除算法会产生内存碎片,为什么不采用标记-整理算法呢?

因为并发清除时,用Compact整理内存的时候,原来用户线程的内存还怎么使用?要保证用户进程能够使用,前提是他运行的资源不受影响Mark-Conpact更适合“Stop The World”下使用

优点:并发收集,低延迟

缺点:

会导致产生内存碎片,用户线程可用空间不足,提前触发full gc

CMS收集器对CPU资源十分敏感

CMS收集器无法处理浮动垃圾

小结

HotSpot有这么多的收集器,那么Serial GC,Parallel GC,CMS GC这三者有什么区别呢?

如果需要最小化的使用内存和并行开销:Serial GC

如果需要最大化应用程序的吞吐量:Parallel GC

如果需要最小化GC的响应时间:CMS GC

4.5G1收集器-区域化分代式

G1(Garbage-First)是一款面向服务端应用的垃圾收集器,主要针对配备多核CPU以及大容量内存的机器,以极高概率满足GC停顿的同时,还兼具高吞吐量的性能特征

是jdk9以后默认的垃圾回收器,取代了CMS,以及Parallel +Parallel Old的组合,被Oracle官方称为“全功能的垃圾收集器”

G1收集器的特点:

并行性:G1在回收期间,可以支持多个GC线程同时工作,有效利用多核计算能力。此时用户线程STW

并发性:G1用于与应用程序交替执行的能力,部分工作可以和应用程序同时执行,因此一般来说,不会整个回收阶段发生完全阻塞应用程序的情况

分代收集

从分代上来看,G1仍然属于分代型垃圾回收器,它会区分年轻代和老年代,年轻代仍然有Ender区和survivor区,但从堆的结构上来看,它不要求整个Ender区,年轻代,老年代都是连续的,也不坚持固定大小和数量

将堆空间分为了若干个区域,这些区域中包含了逻辑上的年轻代和老年代·

和之前的各类回收器不同,它兼顾年轻代和老年代

垃圾回收器总结

img

img

img

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1329382.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PHP下载安装以及基本配置

目录 引言 官网 下载 配置 1. 鼠标右键“此电脑”>“属性” 2. 打开高级系统设置 3. 打开环境变量 4. 双击系统变量中的path 5. 新建新的path 6. 将刚刚安装的位置加入环境变量 7. 检查是否安装成功 引言 PHP("PHP: Hypertext Preprocessor"…

OCC:第一个程序,对话框中显示一个BOX

1. OCC库的获取 从github上获取 gitgithub.com:tpaviot/oce.git,自己编译官网获取二进制包(获取下来的只有release 版本的,而且VS版本不一定适合自己)官网源码,然后自己编译(稍微折腾点,建议按…

【Java】IO流相关操作

目录 常见的文件操作 创建文件 得到文件信息 目录操作 IO流 FileInputStream FileOutputStream FileReader FileWriter BufferedReader BufferedWriter ObjectOutputStream ObjectInputStream InputStreamReader OutputStreamReader PrintStream PrintWriter Properties prope…

【JAVA面试题】基本类型的强制类型转换是否会丢失精度?引用类型的强制类型转换需要注意什么?

🍎个人博客:个人主页 🏆个人专栏: JAVA ⛳️ 功不唐捐,玉汝于成 目录 前言 思路 1、继承关系 2、运行时类型检查 结语 我的其他博客 前言 在Java编程中,强制类型转换是一个常见的操作&#xf…

鸿蒙应用开发ArkTS容器组件的使用

线性布局——Column/Row 线性布局是应用中最常用的布局,通过线性容器 Row 和 Column 构建 线性布局是其他布局的基础,其子元素在水平方向和垂直方向依次排列 线性布局的排列方向由所选容器组件决定,Column 容器内子元素按照垂直方向排列&a…

CSS-计数器 counter-reset、counter-increment、counter-reset

计数器 CSS的计数器通过在 content 上应用 counter() 或 counters()函数来显示计数的。其中计数器是由counter-reset和counter-increment 来进行操作的。 counter-increment 语法 counter-increment参数1:计算器名称 该标识符由不区分大小写的字母 a 到 z&#xf…

服务熔断(Hystrix)

服务雪崩 多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其他的微服务,这就是所谓的“扇出”,如果扇出的链路上某个微服务的调用响应时间过长,或者不可用,对微服务A的…

智能优化算法应用:基于骑手优化算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用:基于骑手优化算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用:基于骑手优化算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.骑手优化算法4.实验参数设定5.算法结果6.…

Open3D 入门教程

文章目录 1、概述2、安装3、点云读写4、点云可视化 4.1、可视化单个点云4.2、同一窗口可视化多个点云4.3、 可视化的属性设置 5、k-d tree 与 Octree 5.1、k-d tree5.2、Octree 5.2.1、从点云中构建Octree5.2.2、从体素栅格中构建 Octree 6、点云滤波 6.1、体素下采样6.2、统计…

java.lang.IllegalStateException: Duplicate key

序言 最近监控扫描出我们项目的某些异常信息,报错java.lang.IllegalStateException: Duplicate key xxx,看到异常来自stream流,然后定位看了一下是某位同事的代码使用stream流把List转Map集合出现重复的key异常信息。List集合A对象来源于某个…

Python命名规范中的[单/双][前导/后缀]下划线小结

如图所示 出处 Single and Double Underscores in Python Names

「C/C++ 01」 深拷贝和浅拷贝

目录 一、概念 1. 浅拷贝 2. 深拷贝 3. 深浅拷贝问题 4. 总结 二、在C的类中实现深拷贝 1. 拷贝构造函数 中实现深拷贝 a. 自己开辟一个新空间,然后将内容拷贝到新空间 b. 借助构造函数来实现深拷贝 2. operator 中实现深拷贝 a. 自己开辟一个新空间,…

JAVA版的鸿鹄云商B2B2C:多商家入驻直播商城系统特性解析 商城免 费搭建

鸿鹄云商 b2b2c产品概述 【b2b2c平台】,以传统电商行业为基石,鸿鹄云商支持“商家入驻平台自营”多运营模式,积极打造“全新市场,全新 模式”企业级b2b2c电商平台,致力干助力各行/互联网创业腾飞并获取更多的收益。从消…

pyqt5实现wget下载视频文件的进度条显示

简介: 最近在写一个项目,用到了wget下载视频,为了更好的视觉效果,所以使用pyqt5中QProgressBar来实现下载进度条。当视频开始下载就会弹出下载进度条,下载完成后进度条消失。效果如下图; 具体代码实现 : …

Sobit:将BRC20资产桥接到Solana ,加速铭文市场的火热

2023 年 1 月份后,比特币 Ordinals 协议出现后为铭文赛道的出现奠定了基础,它以聪为单位将比特币分成份,并在每一聪上攥刻不同的信息以达到非同质化资产的效果,而此后包括 BRC20 在内的诸多采用了 Ordinals 方案的应用不断面向市场…

生成式AI大模型对人类进化的影响

你是不是发现每天的工作都离不开ChatGPT之类的语言生成模型?离不开类似Midjourney的图像生成模型?离不开一些设计类的AI辅助工具?如果是,那说明你已经逐步被AI侵蚀了,你的创造力也正在逐渐下降,大模型正在剥…

使用通道和模式

通过通道、选择语句和最佳实践掌握 Go 中的并发编程 并发编程是构建高效和响应迅速的软件的强大范例。Go,也被称为 Golang,通过通道提供了一种健壮且优雅的解决方案来进行并发通信。在这篇文章中,我们将探讨通道的概念、它们在并发编程中的作…

Qt配置opencv,cmake编译参考笔记,已成功

Qt版本:Qt5.14.2 opencv:4.5.4(不要用4.5.5!!很坑别问我为什么知道) cmake:下的最新版本 前言:为什么非得要用cmake编译呢?跳过cmake不好吗? 之前用的opencv…

pickle反序列化

文章目录 基础知识pickle简介可序列化对象object.__reduce__() 函数 pickle过程详细解读opcode简介pickletools 漏洞利用利用思路如何手写opcode 工具pker实战例题[MTCTF 2022]easypickle[HZNUCTF 2023 preliminary]pickle 基础知识 pickle简介 与PHP类似,python也…

内存管理学习

内存管理 在计算系统中,通常存储空间分为两种:内部存储空间和外部存储空间。 内部存储空间通常访问速度比较快,能够按照变量地址随机访问,也就是我们通常所说的RAM(随机存储器),可以把它理解为…