当前位置: 首页 > news >正文

JVM系列 | 对象的消亡3——垃圾收集器的对比与实现细节

垃圾收集器

文章目录

  • 各收集器简单对比
  • 收集器启动参数
  • 各收集器详细说明
    • JDK 1.3 之前
    • JDK 1.3 | Serial
    • JDK 1.4 | ParNew
    • JDK 1.4 | Parallel Scavenge
    • JDK 5 | CMS 收集器
    • JDK 7 | G1

各收集器简单对比

收集器名称出现时间淘汰时间目标采用技术线程数STW分代备注
无名JDK 1.3之前JDK 1.3标记清除1不分代
SerialJDK 1.3至今仍作为客户端默认的收集器标记复制1新生代/老年代由于简单而高效,仍作为客户端系统的默认垃圾收集器。
ParNewJDK 1.4自JDK9开始只能与CMS搭配只用高效的回收垃圾标记复制默认与核心线程数一样多新生代可以看做是Serial的多线程版本
Parallel ScavengeJDK 1.4至今仍活跃,尤其是需要吞吐量的场景,如大量计算等最大吞吐量标记复制默认与核心线程数一样多新生代吞吐量优先收集器(吞吐量需满足下方公式)
CMSJDK 5JDK9标记为过时/JDK14被正式移除最短回收停顿时间标记清除(处理器核心数量+3)/4老年代第一个可以与用户线程同时工作的垃圾收集器,工作时长更长了,但是用户线程停顿更短饿了
Serial Old不明确/1.2之前JDK之前与Parallel Scavenge,现在一般作为CMS失败的备用方案标记整理1老年代Serial的老年版
Parallel OldJDK 6至今最大吞吐量标记整理N老年代Parallel Scavenge的老年斑
G1/Garbage FirstJDK 7至今时间可控/全功能标记复制NRegion分区G1淘汰了CMS
ShenandoahOpenJDK 12至今10毫秒内垃圾收集标记整理NRegion分区RedHat开发;JDK中没有,只有OpenJDK中才有
ZGCJDK 11至今10毫秒内垃圾收集标记整理NRegion分区使用了读屏障、染色指针和内存多重映射等技术

名词解释:STW(Stop The World)指停止用户线程,该值为否则表示可以与用户线程同时进行。(也许不是整个清理阶段都与用户线程并行,可能只是其中某些阶段)

吞吐量 = 运行用户代码时间 运行用户代码时间 + 运行垃圾收集时间 吞吐量={运行用户代码时间\over{运行用户代码时间+运行垃圾收集时间}} 吞吐量=运行用户代码时间+运行垃圾收集时间运行用户代码时间




收集器启动参数

在本部分中有一些启动项目的命令,这里采用Github开源项目·Zfile进行示例。

收集器名称启动该收集器
Serial-XX:+UseSerialGC
ParNew-XX:+UseParNewGC
Parallel Scavenge-XX:+UseParallelGC
CMS-XX:+UseConcMarkSweepGC
Serial Old使用Serial收集器时,会自动启动Serial Old收集器
Parallel Old-XX:+UseParallelOldGC
G1/Garbage First-XX:+UseG1GC
Shenandoah-XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC

# Serial
java -XX:+UseSerialGC -jar zfile.jar# ParNew
java -XX:+UseParNewGC -jar zfile.jar # ParNew + CMS
java -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -jar zfile.jar# Parallel Scavenge
java -XX:+UseParallelGC -jar zfile.jar
java -XX:+UseParallelGC -XX:GCTimeRatio=1 -jar zfile.jar # 垃圾收集器占比不超过1%
java -XX:+UseParallelGC -XX:+UseAdaptiveSizePolicy -jar zfile.jar # 虚拟机优化内存# CMS
java -XX:+UseConcMarkSweepGC -jar zfile.jar# Parallel Old收集器
java -XX:+UseParallelOldGC -jar zfile.jar# G1
java -XX:+UseG1GC -jar zfile.jar# Shenandoah | 由于现在还在测试阶段,需要使用 -XX:+UnlockExperimentalVMOptions
java -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -jar zfile.jar




各收集器详细说明


JDK 1.3 之前

JDK 1.3 之前并没有一个真正像样的垃圾收集器(据说Serial Old是1.2之前出现的,其余不详),那个时代的垃圾收集器甚至没有一个名字,资料只能搜索到“标记-清除垃圾收集器”,很明显是基于标记清除算法实现的,特点是单线程,需要停止用户线程,没有分代,效率低下等…


JDK 1.3 | Serial

Serial收集器采用标记-清除算法,单线程处理,在进行垃圾收集的时候必须停止用户线程(STW/Stop The World),Serial收集的比较“慢”,这也是一开始都诟病Java慢的主要原因。

但是,Serial的优点是简单,它不需要太多的内存空间,也没有线程切换的资源消耗,就像是一个扫地僧一样默默地进行着自己的工作。而且虽然“慢”,但是一般来说也就只有几十~上百毫秒,虽然这个时间对于服务端程序来说可能十分宝贵,但是对于客户端程序来说无伤大雅,可能你使用的Java App一直每隔一段时间暂停几十毫秒,而你根本察觉不到。正是由于它简单(不消耗太多内存等)高效(相对于其它多线程版本的一条线程来说),所以Serial被广泛使用在客户端程序中。

Serial收集器的工作过程如下(图片来源于《深入理解Java虚拟机》):

在这里插入图片描述

可以看出,每次需要进行垃圾收集的时候,都需要停顿用户线程,且每次只有一个线程在进行垃圾收集


JDK 1.4 | ParNew

ParNew收集器是Serial收集器的多线程版本,在操作上除了是采用多线程的方式来进行的以外,其余与Serial区别不大。需要注意的是:由于ParNew还需要有现成切换的成本,所以其单线程的效率是比Serial低的,也就是说核心数为1时,其工作效率不如Serial收集器。

所以ParNew收集器更适合于核心线程数尚且客观(4~6个)的一些老项目中。


JDK 1.4 | Parallel Scavenge

吞吐量公式说明

Parallel Scavenge是一款吞吐量收集器,主要关注程序的吞吐量,首先了解下吞吐量计算公式:

吞吐量 = 运行用户代码时间 运行用户代码时间 + 运行垃圾收集时间 吞吐量={运行用户代码时间\over{运行用户代码时间+运行垃圾收集时间}} 吞吐量=运行用户代码时间+运行垃圾收集时间运行用户代码时间

如果程序运行需要99毫秒,垃圾回收需要1毫秒,那么吞吐量就是 99/(1 + 99) = 99%。

相关参数

我们可以通过下面一些指令来控制吞吐量,也可以直接控制最大垃圾收集停顿时间等,或者直接将这些参数交给虚拟机来进行控制。

指令接收参数说明
-XX:MaxGCPauseMillis大于0的毫秒数控制最大垃圾收集停顿时间
-XX:GCTimeRatio大于0小于100的整数,也就是垃圾收集时间占总时间的比率直接设置吞吐量大小
-XX:+UseAdaptiveSizePolicy允许虚拟机自动对内存进行调优,从而控制吞吐量

JDK 5 | CMS 收集器

CMS简介

CMS收集器是一种以获取最短回收停顿时间为目标的收集器。目前很大一部分的Java应用集中在互联网网站或者基于浏览器的B/S系统的服务端上,这类应用通常都会较为关注服务的响应速度,希望系统停顿时间尽可能短,以给用户带来良好的交互体验。CMS收集器就非常符合这类应用的需求。

CMS收集器采用标记清除算法,其工作分为四个步骤:

  1. 初始标记:初始标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快

  2. 并发标记(CMS concurrent mark) 与用户线程同时:并发标记阶段就是从GC Roots的直接关联对象开始遍历整个对象图的过程,这个过程耗时较长但是不需要停顿用户线程,可以与垃圾收集线程一起并发运行

  3. 重新标记(CMS remark):重新标记阶段则是为了修正并发标记期间,因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间通常会比初始标记阶段稍长一些,但也远比并发标记阶段的时间短

  4. 并发清除(CMS concurrent sweep) 与用户线程同时:最并发清除阶段,清理删除掉标记阶段判断的已经死亡的对象,由于不需要移动存活对象,所以这个阶段也是可以与用户线程同时并发的

并发清除一定会面临两个问题:浮动垃圾与消失对象问题,CMS采用的是增量更新的解决方案,在之前的博客中已经介绍过了,请点此查看。


CMS的缺点

  1. **处理器资源敏感:**CMS默认启动的回收线程数是(处理器核心数量+3)/4,也就是说,如果处理器核心数在四个或以上,并发回收时垃圾收集线程只占用不超过25%的处理器运算资源,并且会随着处理器核心数量的增加而下降。但是当处理器核心数量不足四个时,CMS对用户程序的影响就可能变得很大。如果应用本来的处理器负载就很高,还要分出一半的运算能力去执行收集器线程,就可能导致用户程序的执行速度忽然大幅降低

  2. Full GC问题:由于CMS收集器无法处理“浮动垃圾”(Floating Garbage),有可能出现“Concurrent Mode Failure”失败进而导致另一次完全“Stop The World”的Full GC的产生(我的理解是由于浮动垃圾的存在导致浪费了一定的空间,并且垃圾收集过程中用户线程还在继续,还在产生新的垃圾,最终内存空间不足导致直接触发FullGC)。因此CMS一般会在内存空间达到一定阈值后直接进行垃圾回收,JDK5默认是68%,JDK6默认为92%,可以通过-XX:CMSInitiatingOccupancyFraction调整阈值大小。

  3. 空间碎片问题:由于CMS是基于标记清除算法进行工作的,这意味着收集结束时会有大量空间碎片产生。空间碎片过多时,将会给大对象分配带来很大麻烦,往往会出现老年代还有很多剩余空间,但就是无法找到足够大的连续空间来分配当前对象,而不得不提前触发一次Full GC的情况。


CMS运行示意图

在这里插入图片描述



JDK 7 | G1

G1收集器具有里程碑式意义,它开创了收集器面向局部收集的设计思路和基于Region的内存布局形式。简单来说,传统的垃圾收集器都是一个老年代,一个新生代,老年代用来存放存活时间较长的对象(或一些大对象),新生代用来存放新对象。而G1收集器采用的是

在G1收集器出现之前的所有其他收集器,包括CMS在内,垃圾收集的目标范围要么是整个新生代(Minor GC),要么就是整个老年代(Major GC),再要么就是整个Java堆(Full GC)。而G1跳出了这个樊笼,它可以面向堆内存任何部分来组成回收集(Collection Set,一般简称CSet)进行回收,衡量标准不再是它属于哪个分代,而是哪块内存中存放的垃圾数量最多,回收收益最大,这就是G1收集器的Mixed GC模式。

简单来说,G1收集器不再是传统的老年代与新生代,而是将连续的Java堆划分为多个大小相等的独立区域(Region),每一个Region都可以根据需要扮演老年代、新生代的角色。G1收集器会根据

Region是最小的的单位,每次垃圾收集的内存空间一定是Region的整数倍。G1会根据回收收益情况,判断回收哪些Region空间。

Region中还有一类特殊的Humongous区域,**专门用来存储大对象。**G1认为只要大小超过了一个Region容量一半的对象即可判定为大对象。每个Region的大小可以通过参数-XX:G1HeapRegionSize设定,取值范围为1MB~32MB,且应为2的N次幂。而对于那些超过了整个Region容量的超级大对象,将会被存放在N个连续的Humongous Region之中,G1的大多数行为都把Humongous Region作为老年代的一部分来进行看待。

在这里插入图片描述


产生的问题与解决方案

**跨区引用问题:**每个Region都维护有自己的记忆集,这些记忆集会记录下别的Region指向自己的指针,并标记这些指针分别在哪些卡页的范围之内。G1的记忆集在存储结构的本质上是一种哈希表,Key是别的Region的起始地址,Value是一个集合,里面存储的元素是卡表的索引号。这种“双向”的卡表结构(卡表是“我指向谁”,这种结构还记录了“谁指向我”)比原来的卡表实现起来更复杂,同时由于Region数量比传统收集器的分代数量明显要多得多,因此G1收集器要比其他的传统垃圾收集器有着更高的内存占用负担。

**收集线程与用户线程互不干扰的运行:**首先要解决的是用户线程改变对象引用关系时,必须保证其不能打破原本的对象图结构,导致标记结果出现错误(见《HotSpot实现细节-原是快照》);此外,垃圾收集对用户线程的影响还体现在回收过程中新创建对象的内存分配上,程序要继续运行就肯定会持续有新对象被创建,G1为每一个Region设计了两个名为TAMS(Top at Mark Start)的指针,把Region中的一部分空间划分出来用于并发回收过程中的新对象分配,并发回收时新分配的对象地址都必须要在这两个指针位置以上。G1收集器默认在这个地址以上的对象是被隐式标记过的,即默认它们是存活的,不纳入回收范围。与CMS中的“Concurrent Mode Failure”失败会导致Full GC类似,如果内存回收的速度赶不上内存分配的速度,G1收集器也要被迫冻结用户线程执行,导致Full GC而产生长时间“Stop The World”。

**怎样建立起可靠的停顿预测模型?**用户通过-XX:MaxGCPauseMillis参数指定的停顿时间只意味着垃圾收集发生之前的期望值,但G1收集器要怎么做才能满足用户的期望呢?G1收集器的停顿预测模型是以衰减均值(Decaying Average)为理论基础来实现的,在垃圾收集过程中,G1收集器会记录每个Region的回收耗时、每个Region记忆集里的脏卡数量等各个可测量的步骤花费的成本,并分析得出平均值、标准偏差、置信度等统计信息。这里强调的“衰减平均值”是指它会比普通的平均值更容易受到新数据的影响,平均值代表整体平均状态,但衰减平均值更准确地代表“最近的”平均状态。换句话说,Region的统计状态越新越能决定其回收的价值。然后通过这些信息预测现在开始回收的话,由哪些Region组成回收集才可以在不超过期望停顿时间的约束下获得最高的收益。


回收过程

  1. **初始标记(Initial Marking):**仅仅只是标记一下GC Roots能直接关联到的对象,并且修改TAMS指针的值,让下一阶段用户线程并发运行时,能正确地在可用的Region中分配新对象。这个阶段需要停顿线程,但耗时很短,而且是借用进行Minor GC的时候同步完成的,所以G1收集器在这个阶段实际并没有额外的停顿。

  2. **并发标记(Concurrent Marking):**从GC Root开始对堆中对象进行可达性分析,递归扫描整个堆里的对象图,找出要回收的对象,这阶段耗时较长,但可与用户程序并发执行。当对象图扫描完成以后,还要重新处理SATB记录下的在并发时有引用变动的对象。

  3. **最终标记(Final Marking):**对用户线程做另一个短暂的暂停,用于处理并发阶段结束后仍遗留下来的最后那少量的SATB记录。

  4. **筛选回收(Live Data Counting and Evacuation):**负责更新Region的统计数据,对各个Region的回收价值和成本进行排序,根据用户所期望的停顿时间来制定回收计划,可以自由选择任意多个Region构成回收集,然后把决定回收的那一部分Region的存活对象复制到空的Region中,再清理掉整个旧Region的全部空间。这里的操作涉及存活对象的移动,是必须暂停用户线程,由多条收集器线程并行完成的。

在这里插入图片描述

相关文章:

JVM系列 | 对象的消亡3——垃圾收集器的对比与实现细节

垃圾收集器 文章目录 各收集器简单对比收集器启动参数各收集器详细说明JDK 1.3 之前JDK 1.3 | SerialJDK 1.4 | ParNewJDK 1.4 | Parallel ScavengeJDK 5 | CMS 收集器JDK 7 | G1 各收集器简单对比 收集器名称出现时间淘汰时间目标采用技术线程数STW分代备注无名JDK 1.3之前JD…...

C# Unity 面向对象补全计划 七大原则 之 开闭原则(OCP) 难度:☆ 总结:已经写好的就别动它了,多用继承

本文仅作学习笔记与交流,不作任何商业用途,作者能力有限,如有不足还请斧正 本系列作为七大原则和设计模式的进阶知识,看不懂没关系 请看专栏:http://t.csdnimg.cn/mIitr,查漏补缺 1.开闭原则(OC…...

微信防封指南请收好

一、新号与老号的添加限制 建议新注册的微信号主动添加好友的数量不宜过多,推荐每日添加不超过5个好友;对于老号,建议每日添加不超过20个好友。保持适度的添加速度,避免被系统判定为异常操作。 二、避免使用营销性词汇 在发送消…...

选择排序算法改进思路和算法实现

选择排序 在未排序的数组中,用第一个数去和后面的数比较,找出最小的数,和第一个数交换。第一个数已为已排序的数。 相当于0~7 从0~7中找到最小的数放在0 从1~7中找到最小的数放在1 从2~7中找到最小的数放在2 ...以此类推 从6~7中找到最…...

【文件解析漏洞复现】

一.IIS解析漏洞复现 1.IIS6.X 方式一:目录解析 搭建IIS环境 在网站下建立文件夹的名字为.asp/.asa 的文件夹,其目录内的任何扩展名的文件都被IIS当作asp文件来解析并执行。 访问成功被解析 方式一:目录解析 在IIS 6处理文件解…...

【STL】 vector的底层实现

1.vector的模拟代码完整实现&#xff08;后面会拆分开一个一个细讲&#xff09; #pragma once #include<assert.h>// 抓重点namespace bit {/*template<class T>class vector{public:typedef T* iterator;private:T* _a;size_t _size;size_t _capacity;};*/templa…...

责任链模式:解耦职责,优化请求处理

在软件设计中&#xff0c;如何有效地处理复杂的请求是一个重要的课题。 责任链模式&#xff08;Chain of Responsibility Pattern&#xff09;提供了一种解耦请求发送者和接收者的方法&#xff0c;使得多个对象都有机会处理请求&#xff0c;从而达到灵活和可扩展的设计。 什么…...

【Scene Transformer】scene transformer论文阅读笔记

文章目录 序言(Abstract)(Introduction)(Related Work)(Methods)(Scene-centric Representation for Agents and Road Graphs)(Encoding Transformer)(Predicting Probabilities for Each Futures)(Joint and Marginal Loss Formulation) (Results)(Discussion)(Questions) sce…...

ESP32在ESP-IDF环境下禁用看门狗

最近使用了一款ESP32的开发板。但在调试时发现出现许多看门狗复位事件&#xff1a; E (8296) task_wdt: Task watchdog got triggered. The following tasks/users did not reset the watchdog in time: E (8296) task_wdt: - IDLE (CPU 0) E (8296) task_wdt: Tasks curre…...

基于 uniapp html5plus API,怎么把图片保存到相册

要将图片保存到相册中&#xff0c;可以使用HTML5 API中的plus.gallery.save方法。以下是一个示例代码&#xff0c;展示如何将图片保存到手机相册&#xff1a; // 图片的URL&#xff0c;可以是本地路径或网络路径 var imageUrl path/to/your/image.jpg;// 调用plus.gallery.sa…...

3.特征工程-特征抽取、特征预处理、特征降维

文章目录 环境配置&#xff08;必看&#xff09;头文件引用1.数据集: sklearn代码运行结果 2.字典特征抽取: DictVectorizer代码运行结果稀疏矩阵 3.文本特征抽取(英文文本): CountVectorizer()代码运行结果 4.中文文本分词(中文文本特征抽取使用)代码运行结果 5.中文文本特征抽…...

RISC-V (五)上下文切换和协作式多任务

任务&#xff08;task&#xff09; 所谓的任务就是寄存器的当前值。 -smp后面的数字指的是hart的个数&#xff0c;qemu模拟器最大可以有8个核&#xff0c;此文围绕一个核来讲。 QEMU qemu-system-riscv32 QFLAG -nographic -smp 1 -machine virt -bios none 协作式多任务 …...

Cornerstone加载本地Dicom文件第二弹 - Blob篇

&#x1f340; 引言 当我们刚接触Cornerstone或拿到一组Dicom文件时&#xff0c;如果没有ImageID和后台接口&#xff0c;可能只是想简单测试Cornerstone能否加载这些Dicom文件。在这种情况下&#xff0c;可以使用本地文件加载的方法。之前我们介绍了通过node启动服务器请求文件…...

C语言中整数类型及其类型转换

1.数据的存储和排列 是的&#xff0c;在C语言中&#xff0c;整数类型通常以补码&#xff08;twos complement&#xff09;形式存储在内存中。这是因为补码表示法在处理有符号整数的加减运算上更为简便和高效。 2.有符号数和无符号数之间的转换 在C语言中&#xff0c;有符号数和…...

powerjob连接postgresql数据库(支持docker部署)

1.先去pg建一个powerjob-product库 2.首先去拉最新的包&#xff0c;然后找到server模块&#xff0c;把mysql的配置文件信息替换成pg的 spring.datasource.hikari.auto-committrue spring.datasource.remote.hibernate.properties.hibernate.dialecttech.powerjob.server.pers…...

浅谈位运算及其应用(c++)

目录 一、位运算的基础&#xff08;一&#xff09;位与&#xff08;&&#xff09;&#xff08;二&#xff09;位或&#xff08;|&#xff09;&#xff08;三&#xff09;位异或&#xff08;^&#xff09;&#xff08;四&#xff09;位取反&#xff08;~&#xff09;&#x…...

Git版本管理中下列不适于Git的本地工作区域的是

Git版本管理中下列不适于Git的本地工作区域的是 A. 工作目录 B. 代码区 C. 暂存区 D. 资源库 选择B Git本地有四个工作区域&#xff1a; 工作目录&#xff08;Working Directory&#xff09;、 暂存区(Stage/Index)、 资源库(Repository或Git Directory)、 git仓库(Remote Di…...

webGL + WebGIS + 数据可视化

webGL&#xff1a; 解释&#xff1a;用于在浏览器中渲染 2D 和 3D 图形。它是基于 OpenGL ES 的&#xff0c;提供了直接操作 GPU 的能力。 库&#xff1a; Three.jsBabylon.jsPixiJSReglGlMatrixOsgjs WebGIS&#xff1a; 解释&#xff1a;用于在 Web 浏览器中处理和展示地…...

职场“老油条”的常规操作,会让你少走许多弯路,尤其这三点

有句话说得好&#xff1a;“在成长的路上&#xff0c;要么受教育&#xff0c;要么受教训。” 挨过打才知道疼&#xff0c;吃过亏才变聪明&#xff0c;从职场“老油条”身上能学到很多经验&#xff0c;不一定全对&#xff0c;但至少有可以借鉴的地方&#xff0c;至少能让你少走…...

Ceres Cuda加速

文章目录 一、简介二、准备工作三、实现代码四、实现效果参考资料一、简介 字Ceres2.2.1版本之后,作者针对于稠密矩阵的分解计算等操作进行了Cuda加速,因此这里就基于此项改动测试一下效果。 二、准备工作 1、首先是需要安装Cuda这个英伟达第三方库,https://developer.nvidi…...

【网络】每天掌握一个Linux命令 - iftop

在Linux系统中&#xff0c;iftop是网络管理的得力助手&#xff0c;能实时监控网络流量、连接情况等&#xff0c;帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频

使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

【位运算】消失的两个数字(hard)

消失的两个数字&#xff08;hard&#xff09; 题⽬描述&#xff1a;解法&#xff08;位运算&#xff09;&#xff1a;Java 算法代码&#xff1a;更简便代码 题⽬链接&#xff1a;⾯试题 17.19. 消失的两个数字 题⽬描述&#xff1a; 给定⼀个数组&#xff0c;包含从 1 到 N 所有…...

React19源码系列之 事件插件系统

事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

P3 QT项目----记事本(3.8)

3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

Python爬虫(二):爬虫完整流程

爬虫完整流程详解&#xff08;7大核心步骤实战技巧&#xff09; 一、爬虫完整工作流程 以下是爬虫开发的完整流程&#xff0c;我将结合具体技术点和实战经验展开说明&#xff1a; 1. 目标分析与前期准备 网站技术分析&#xff1a; 使用浏览器开发者工具&#xff08;F12&…...

浅谈不同二分算法的查找情况

二分算法原理比较简单&#xff0c;但是实际的算法模板却有很多&#xff0c;这一切都源于二分查找问题中的复杂情况和二分算法的边界处理&#xff0c;以下是博主对一些二分算法查找的情况分析。 需要说明的是&#xff0c;以下二分算法都是基于有序序列为升序有序的情况&#xf…...

优选算法第十二讲:队列 + 宽搜 优先级队列

优选算法第十二讲&#xff1a;队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

push [特殊字符] present

push &#x1f19a; present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中&#xff0c;push 和 present 是两种不同的视图控制器切换方式&#xff0c;它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...