关于v8垃圾回收机制联想到的知识点

对于值类型b来说,就直接释放了其占用的内存,对于引用类型obj来说,销毁的只是变量obj对堆内存地址 1001 的引用,obj的值 { c: 3 } 依然存在于堆内存中。那么堆内存中的变量如何进行回收呢?

  • V8的垃圾回收策略主要是基于分代式垃圾回收机制,其根据对象的存活时间将内存的垃圾回收进行不同的分代,然后对不同的分代采用不同的垃圾回收算法。
  • 在新生代的垃圾回收过程中主要采用了Scavenge算法;在老生代采用标记清除标记整理算法。

============================

全停顿

垃圾回收算法在执行前,需要将应用逻辑暂停,执行完垃圾回收后再执行应用逻辑,这种行为称为 「全停顿」。例如,如果一次GC需要50ms,应用逻辑就会暂停50ms。

全停顿的目的,是为了解决应用逻辑与垃圾回收器看到的情况不一致的问题。

JavaScript中会被判定为垃圾的情形如下:

  • 对象不再被引用;
  • 对象不能从根上访问到;

GC算法

常见的GC算法如下:

  • 引用计数
  • 标记清除
  • 标记整理
  • 分代回收

浏览器的垃圾回收机制:

浏览器垃圾回收机制根据数据的存储方式分为栈垃圾回收和堆垃圾回收

栈垃圾回收,当一个函数执行结束之后,JavaScript 引擎会通过向下移动 ESP 来销毁该函数保存在栈中的执行上下文,遵循先进后出的原则。

堆垃圾回收,当函数直接结束,栈空间处理完成了,但是堆空间的数据虽然没有被引用,但是还是存储在堆空间中,需要垃圾回收器将堆空间中的垃圾数据回收。

在V8中,将内存一分为二,分为了新生代和老生代。它们特点如下:

  • 新生代:对象的存活时间较短。新生的对象或只经过一次垃圾回收的对象。
  • 老生代:对象存活时间较长。经历过一次或多次垃圾回收的对象。

我们可以通过 --max-old-space-size命令设置老生代空间的最大值,--max-new-space-size 命令设置新生代空间的最大值。老生代与新生代的空间大小在程序初始化时设置,一旦生效则不能动态改变。

新生区中使用Scavenge(清除)算法,老生区中使用标记-清除算法和标记-整理算法。

新生代垃圾回收(副垃圾回收器)

新生代的特点:

  • 通常把小的对象分配到新生代
  • 新生代的垃圾回收比较频繁
  • 通常存储容量在1~8M

新生代中垃圾回收算法:

Scavenge算法:标记->复制->角色反转

回收新生代对象主要采用复制算法Scavenge 算法)加标记整理算法。而Scavenge 算法的具体实现,主要采用了Cheney算法

image

Cheney算法将内存分为两个等大空间,使用空间为From,空闲空间为To

过程如下:

  1. 从 From 空间分配对象,若 semispace 被分配满,则执行 Scavenge 算法进行垃圾回收。
  2. 对对象区域中的垃圾进行标记,检查 From 空间的存活对象,若对象存活,则检查对象是否符合晋升条件,若符合条件则晋升到老生代,否则将对象从 From 空间复制到 To 空间。并且有序的排列起来,复制后空闲区域就没有内存碎片了
  3. 若对象不存活,则释放不存活对象的空间。
  4. 完成复制后,将 From空间(对象区域)与 To 空间(空闲区域)进行角色翻转(flip)。这样就完成了垃圾对象的回收操作,同时这种角色翻转的操作还能让新生代中的这两块区域无限重复使用下去

一轮GC还存活的新生代需要晋升。
当对象从From 空间复制到 To 空间时,若 To 空间使用超过 25%,则对象直接晋升到老生代中。

缺点:由于只能使用堆内存的一半,所以不适用大规模的垃圾回收机制中

在讲解老生代Mark-Sweep(标记清除)Mark-Compact(标记整理)算法之前,先来回顾一下引用计数法:对于对象A,任何一个对象引用了A的值,计数器+1,引用失效时计数器-1,当计数器为0时责备回收,但是会存在循环引用的情况,可能会导致内存泄漏,自2012年起,所有的现代浏览器均放弃了这种算法。

 引用计数

早期的浏览器最常使用的垃圾回收方法叫做"引用计数":语言引擎有一张"引用表",保存了内存里面所有的资源(通常是各种值)的引用次数。如果一个值的引用次数是0,就表示这个值不再用到了,因此可以将这块内存释放。

引用计数有一个问题就是:循环引用

引用计数算法优点:

  • 引用计数为零时,发现垃圾立即回收;
  • 最大限度减少程序暂停;

引用计数算法缺点:

  • 无法回收循环引用的对象;
  • 空间开销比较大;

老生代垃圾回收(主垃圾收集器)

因为新生代存储容量小,很容易写满,所以经过两次垃圾回收之后依然活动的对象,就会被移动到老生代中,这个策略被称为对象晋升策略

晋升条件:
对象晋升的条件主要有两个。
1、对象在新生代期间是否经历过Scavenge回收;
2、是To空间的内存占用比超过限制(To空间内存消耗是否超过25%,如果超过对象直接晋升)(设置为25%的比例的原因是,当完成 Scavenge 回收后,To 空间将翻转成From 空间,继续进行对象内存的分配。若占比过大,将影响后续内存分配,因此超过这个限制之后对象会被直接转移到老生代来进行管理)
————————————————
                       

回收老生代对象主要采用标记清除标记整理增量标记算法,主要使用标记清除算法,只有在内存分配不足时,采用标记整理算法。

  1. 首先使用标记清除完成垃圾空间的回收
  2. 采用标记整理进行空间优化
  3. 采用增量标记进行效率优化

 标记清除

核心思想:分标记和清除两个阶段完成。

标记:标记阶段就是从一组根元素开始,递归遍历这组根元素,在这个遍历过程中,能到达的元素称为活动对象,没有到达的元素就可以判断为垃圾数据。(标记存活的对象)
清除:将垃圾数据进行清除。

对比引用计数算法,标记清除算法最大的优点是能够回收循环引用的对象,它也是v8引擎使用最多的算法。
缺点:对一块内存多次执行标记 - 清除算法后,会产生大量不连续的内存碎片。而碎片过多会导致大对象无法分配到足够的连续内存。此时需要对内存碎片进行整理。

这种内存碎片会对后续的内存分配造成问题,因为很可能出现需要分配一个大对象的情况,这时所有的碎片空间都无法完成此次分配,就会提前触发垃圾回收,而这次回收是不必要的。

标记整理

与标记清除呈现一个策略递进关系,当空间不足以对从新生代中晋升过来的对象进行分配时才使用,在整理的过程中,将活着的对象往一端移动,移动完成后,直接清理掉边界外的内存。这也是两者最大的区别。标记整理对待未存活对象不是⽴即回收,⽽是将存活对象移动到⼀边,然后直接清掉端边界以外的内存。

1. 标记:和标记 - 清除的标记过程一样,从一组根元素开始,递归遍历这组根元素,在这个遍历过程中,能到达的元素标记为活动对象。

2. 整理:让所有存活的对象都向内存的一端移动

3. 清除:清理掉边界以外的内存

 V8 是使用副垃圾回收器和主垃圾回收器处理垃圾回收的,不过由于 JavaScript 是运行在主线程之上的,一旦执行垃圾回收算法,都需要将正在执行的 JS 脚本暂停下来,待垃圾回收完毕后再恢复脚本执行。这种行为叫做全停顿。 为了降低老生代的垃圾回收而造成的卡顿,V8 将标记过程分为一个个的子标记过程,同时让垃圾回收标记和 JS 应用逻辑交替进行,直到标记阶段完成,这个算法称为增量标记


这里为了便于理解,引用两个流程图。

增量标记

新生代和老生代回收对比

新生代由于占用空间比较少,采用空间换时间机制。
老生代区域空间比较大,不太适合大量的复制算法和标记整理,所以最常用的是标记清除算法,为了就是让全停顿的时间尽量减少。

=======================================================

全停顿


V8 是使用副和主垃圾回收器处理垃圾回收的,不过由于 js是运行在主线程之上的,一旦执行垃圾回收算法,都需要将正在执行的js 脚本暂停下来,待垃圾回收完毕后再恢复脚本执行。我们把这种行为叫做全停顿(Stop-The-World)。

将原本需要一次性遍历堆内存的操作改为增量标记的方式,先标记堆内存中的一部分对象,然后暂停,将执行权重新交给JS主线程,待主线程任务执行完毕后再从原来暂停标记的地方继续标记,直到标记完整个堆内存。
即:把垃圾回收这个⼤的任务分成⼀个个⼩任务,穿插在 JavaScript任务中间执⾏

这个理念其实有点像React框架中的Fiber架构,只有在浏览器的空闲时间才会去遍历Fiber Tree执行对应的任务,否则延迟执行,尽可能少地影响主线程的任务,避免应用卡顿,提升应用性能。

得益于增量标记的好处,V8引擎后续继续引入了延迟清理(lazy sweeping)和增量式整理(incremental compaction),让清理和整理的过程也变成增量式的。同时为了充分利用多核CPU的性能,也将引入并行标记和并行清理,进一步地减少垃圾回收对主线程的影响,为应用提升更多的性能。
 

识别内存泄漏的方法 :performance

点击 检查的performance 然后点击录制 执行我们觉得比较消耗内存的操作 然后stop录制。

可以看到内存在短时间消耗的比较快,下降的小凹槽,就是浏览器在进行垃圾回收

垃圾回收优化策略


1.延迟回收:

因为垃圾hi收会有一个运行的阻塞,所以可以选择在cpu空闲时候时候进行垃圾回收,从而尽可能减少对应用程序运行的影响

2.增量标记:

由于全堆垃圾回收会导致JS应用暂停执行,为了减少全堆垃圾回收带来的卡顿,V8采用增量标记的策略。也就是将一次完整的垃圾回收分解为多个小的步骤,同时让垃圾回收和应用逻辑交替执行,以达到流畅的用户体验。

3.对象晋升:

在新生代中存活下来的对象会被移动到老生代中,这就是对象晋升策略。在V8中通常采用两次垃圾回收后仍然存活的对象会被晋升到老生代。

当进行大规模的垃圾回收时,V8引擎使用增量标记来减少对应用程序的阻塞。

增量标记是一种垃圾回收的优化策略,它将一次完整的垃圾回收过程分解为多个小的步骤,使得垃圾回收和应用程序的逻辑可以交替执行。这样可以减少垃圾回收造成的长时间阻塞,提高应用程序的响应性和用户体验。

V8引擎的增量标记策略主要包括以下步骤:

初始标记(Initial Marking):在这个阶段,V8会标记出根对象和直接从根对象可达的对象,确定它们为活动对象。这个阶段需要阻塞应用程序的执行,但是尽量保持时间短暂。

并发标记(Concurrent Marking):在初始标记之后,V8引擎会启动增量标记线程,与应用程序的执行并发进行。增量标记线程会遍历剩余的对象图,标记出所有的活动对象。同时,应用程序的逻辑也在继续执行。

再标记(Remark):在并发标记过程中,应用程序可能会继续修改对象的引用关系,因此需要进行再标记。再标记阶段会对并发标记过程中发生变化的对象进行重新标记,以确保准确性。

清除阶段(Sweeping):在增量标记完成后,V8引擎会进行清除阶段,回收非活动对象所占用的内存。这个阶段通常会阻塞应用程序的执行,因为它需要遍历堆中的所有对象。

通过增量标记的方式,V8引擎可以在垃圾回收过程中与应用程序的逻辑交替执行,减少长时间的阻塞。这种方式可以有效降低垃圾回收对应用程序性能的影响,提高应用程序的响应速度和用户体验。


————————————————

性能优化即如何避免内存泄漏:

1.尽可能减少全局变量的使用

1.避免使用全局变量

  • 全局变量会挂载在window下;
  • 全局变量至少有一个引用计数;
  • 全局变量存活更久,持续占用内存;
  • 在明确数据作用域的情况下,尽量使用局部变量;如果确实需要使用全局变量,确保在使用完毕后将其设置为 null,以便垃圾回收机制可以及时释放内存。

2.手动清除定时器以及不用闭包


在使用定时器时,一定要记得在适当的时机手动清除定时器。如果忘记清除定时器,定时器的回调函数将持续执行,可能导致内存泄漏。确保在不需要定时器时,使用 clearTimeout 或 clearInterval 主动清除定时器。

3.清除 DOM 引用

当操作 DOM 元素时,确保在不再需要使用它们时清除对 DOM 元素的引用。如果仍然保留对已移除或隐藏的 DOM 元素的引用,这些元素将无法被垃圾回收。

4.使用弱引用weakMap

5.减少判断层级

function doSomething(part, chapter) {const parts = ['ES2016', '工程化', 'Vue', 'React', 'Node']if (part) {if (parts.includes(part)) {console.log('属于当前课程')if (chapter > 5) {console.log('您需要提供 VIP 身份')}}} else {console.log('请确认模块信息')}
}doSomething('Vue', 6)// 减少判断层级
function doSomething(part, chapter) {const parts = ['ES2016', '工程化', 'Vue', 'React', 'Node']if (!part) {console.log('请确认模块信息')return}if (!parts.includes(part)) returnconsole.log('属于当前课程')if (chapter > 5) {console.log('您需要提供 VIP 身份')}
}doSomething('Vue', 6)

6.减少数据读取次数
对于频繁使用的数据,我们要对数据进行缓存。

<div id="skip" class="skip"></div><script>var oBox = document.getElementById('skip')// function hasEle (ele, cls) {//     return ele.className === cls// }function hasEle (ele, cls) {const className = ele.classNamereturn className === cls}console.log(hasEle(oBox, 'skip'))
</script>

7.事件绑定优化

<ul class="ul"><li>Hello World!</li><li>25</li><li>岂曰无衣,与子同袍</li>
</ul><script>var list = document.querySelectorAll('li')function showTxt(ev) {console.log(ev.target.innerHTML)}for (item of list) {item.onclick = showTxt}// 优化后function showTxt(ev) {var target = ev.targetif (target.nodeName.toLowerCase() === 'li') {console.log(ev.target.innerHTML)}}var ul = document.querySelector('.ul')ul.addEventListener('click', showTxt)
</script>

        8.避开闭包陷阱

<button class="btn">点击</button><script>function foo() {let el = document.querySelector('.btn')el.onclick = function() {console.log(el.className)}}foo()// 优化后function foo1() {let el = document.querySelector('.btn')el.onclick = function() {console.log(el.className)}el = null // 将el置为 null 防止闭包中的引用使得不能被回收}foo1()
</script>

与weakMap的关联

通过【垃圾回收机制】的角度认识【Map与WeakMap】的区别 - 知乎 (zhihu.com)

V8 垃圾回收机制与 WeakMap 之间有一些联系,主要涉及到垃圾回收对于弱引用的处理。以下是它们之间的关系:

1.弱引用和垃圾回收: WeakMap 中的键是弱引用的。这意味着,如果没有其他引用指向 WeakMap 中的键对象,这些键对象可以被垃圾回收。垃圾回收器在执行时会检测并处理弱引用,当检测到某个对象的引用计数为零时,可以安全地回收该对象。
2.避免内存泄漏: 由于 WeakMap 的键是弱引用,当键对象不再被其他部分引用时,它们可以被垃圾回收,相应的键值对也会从 WeakMap 中自动删除。这有助于防止一些潜在的内存泄漏问题,因为对象在 WeakMap 中的存在不会阻止它们被垃圾回收。
3.私有数据存储: WeakMap 通常被用于存储对象的私有数据,因为这样的数据不会影响对象的垃圾回收。这使得在不破坏封装性的情况下关联额外信息成为可能。

let weakMap = new WeakMap();let obj = {};
weakMap.set(obj, "some private data");// 当 obj 不再被引用时,垃圾回收可以回收 obj,并清理 weakMap 中对应的项。
obj = null;

总体而言,WeakMap 的设计与垃圾回收机制的协同工作有助于更有效地管理对象的生命周期,避免潜在的内存泄漏问题,同时提供一种安全地存储私有数据的机制。

Map和WeakMap都是JavaScript的内置数据结构,用于存储键值对。它们之间的主要区别在于以下几点:

  1. 键类型的限制:在Map中,键可以是任意类型的值(包括基本类型和对象引用),而在WeakMap中,键只能是对象引用。这是因为WeakMap的键是弱引用,不会阻止对象被垃圾回收,使得WeakMap更适合于存储对象之间的关联信息。
  2. 垃圾回收机制:在Map中,如果某个键不再被引用,它仍然会被Map引用,并且不会被垃圾回收。而在WeakMap中,如果某个键不再被引用,它会被自动从WeakMap中删除,这也是WeakMap的一个特性,可以避免内存泄漏。
  3. 迭代:在Map中,可以使用Map.prototype.keys()Map.prototype.values()Map.prototype.entries()等方法来迭代Map中的键、值或键值对,而在WeakMap中,由于键是对象引用,无法直接迭代键或值。
  4. 功能:Map相比WeakMap提供了更多的功能,比如可以获取Map的大小(使用Map.prototype.size属性),可以通过键获取值(使用Map.prototype.get()方法),可以遍历Map中的键值对等。而WeakMap相对简单,只提供了WeakMap.prototype.get()WeakMap.prototype.set()WeakMap.prototype.has()WeakMap.prototype.delete()等基本操作。

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

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

相关文章

怎么录制屏幕视频?让你的视频脱颖而出

随着科技的飞速发展&#xff0c;录制屏幕视频已经成为人们日常学习和工作中不可或缺的技能。无论是制作教程、分享游戏高光时刻&#xff0c;还是保存线上会议的内容&#xff0c;屏幕录制都可以帮助我们更好地传达信息。可是怎么录制屏幕视频呢&#xff1f;本文将介绍两种录制屏…

手把手教你如何将项目发布到Maven中央仓库(附步骤及常见问题解决方法)

手把手教你如何将项目发布到Maven中央仓库(附步骤及常见问题解决方法) 业余时间写了个轻量级的权限控制框架 light-security &#xff0c;并发布到了 Maven 中央仓库。发布时的操作步骤还挺多&#xff0c;我这个记性是记不住的&#xff0c;所以记录一下&#xff0c;便于以后查…

【C++】 C++入门— 基于范围的 for 循环

C 基于范围的for循环1 使用样例2 使用条件3 完善措施 Thanks♪(&#xff65;ω&#xff65;)&#xff89;谢谢阅读&#xff01;下一篇文章见&#xff01;&#xff01;&#xff01; 基于范围的for循环 1 使用样例 使用for循环遍历数组&#xff0c;我们通常这么写&#xff1a; …

3D打印、自动升降超静电机驱动方案TMC2209

TMC2209步进电机驱动芯片介绍 TMC2209是一款用于两相步进电机的超静音电机驱动IC。Trinamic的精密StealthChop波器确保了无噪音运行、最大效率和最佳电机转矩。它的快速电流调节和与SpreadCycle的可选组合允许高度动态运动&#xff0c;同时为无传感器归位添加了StallGuard4。集…

python中的可变与不可变、深拷贝和浅拷贝

个人猜想&#xff08;很遗憾失败了&#xff09; 在硬盘或者系统中存在一个字符集 如果存在硬盘中&#xff0c;那么硬盘出厂的时候他的字符集所占用的空间就已经确定了。 如果存在于系统的话&#xff0c;硬盘应该在出厂的时候为系统设置一个存储系统字符集的地方。在安装系统…

L1-019 谁先倒分数 15

划拳是古老中国酒文化的一个有趣的组成部分。酒桌上两人划拳的方法为&#xff1a;每人口中喊出一个数字&#xff0c;同时用手比划出一个数字。如果谁比划出的数字正好等于两人喊出的数字之和&#xff0c;谁就输了&#xff0c;输家罚一杯酒。两人同赢或两人同输则继续下一轮&…

2024/2/4周报

文章目录 摘要Abstract文献阅读题目引言创新点方法利用长短期记忆网络学习时空演化特征构建用于气象辅助信息编码的堆叠自编码器使用多任务学习发现全市通用模式 模型实验数据集评估准则实验结果 深度学习Self-attentionself-Attention由来self-attention原理self attention代码…

【ArcGIS微课1000例】0100:ArcGIS for CAD软件下载与安装(附安装包)

ArcGIS for CAD软件下载与安装(附安装包)。 文章目录 一、ArcGIS for CAD概述1. ArcGIS for CAD介绍2. 主要功能二、ArcGIS for CAD下载三、ArcGIS for CAD安装1. 安装CAD2. 安装ArcGIS for CAD3. 配置一、ArcGIS for CAD概述 1. ArcGIS for CAD介绍 ArcGIS for CAD是Esri提…

《拳皇97》中的人物性格——陈可汗

在热血沸腾、高手如云的《拳皇97》世界里,有一位壮硕威猛却自带喜感的角色引人注目,他就是我们的重量级选手——陈可汗。这位来自中国的摔跤手以其独特的性格特质和生动活泼的表现方式,在激烈的格斗赛场上描绘出了一幅既令人捧腹又充满力量的画面。 陈可汗甫一登场,那魁梧的…

Acwing---2816. 判断子序列

判断子序列 1.题目2.基本思想3.代码实现 1.题目 给定一个长度为 n n n 的整数序列 a 1 , a 2 , … , a n a1,a2,…,an a1,a2,…,an 以及一个长度为 m m m 的整数序列 b 1 , b 2 , … , b m b1,b2,…,bm b1,b2,…,bm。 请你判断 a a a序列是否为 b b b序列的子序列。 子…

解锁影视制作新境界:DaVinci Resolve Studio 18引领行业变革

随着科技的不断发展&#xff0c;影视制作行业也在日新月异地变革。在这一进程中&#xff0c;DaVinci Resolve Studio 18以其卓越的性能和无限的创新力&#xff0c;成为了行业的领跑者。 DaVinci Resolve Studio 18是一款集剪辑、调色、音频处理和特效合成于一身的专业级影视制…

CICD注册和使用gitlab-runner常见问题

1、现象 fatal: unable to access https://github.com/homebrew/brew/: 2、解决 git config --global --unset http.proxy git config --global --unset https.proxy 查看gitlab-runner是否成功&#xff1a; userusers-MacBook-Pro ~ % gitlab-runner -h 查看gitlab-run…

openssl3.2 - 帮助文档的整理

文章目录 openssl3.2 - 帮助文档的整理概述笔记整理后, 非空的文件夹如下整理后, 留下的有点用的文件列表如下备注END openssl3.2 - 帮助文档的整理 概述 openssl3.2源码工程编译安装完, 对于库的使用者, 有用的文档, 远不止安装的那些html. 用everything查找, 配合手工删除,…

使用python-pandas对比两个结构相同的文件差异,并输出差集文件的方法

最近在处理数据相关需求&#xff0c;遇到一个问题&#xff1a;两个文件&#xff0c;fileA.csv和fileB.csv&#xff0c;结构相同&#xff0c;fileA包含fileB的内容&#xff0c;但是需要得到二者的差集&#xff0c;输出新的文件fileC。 经过查询资料&#xff0c;发现pandas可以很…

康姿百德床垫价格合理功效好,用科技力量守护您的睡眠健康

现代生活中&#xff0c;优质睡眠的观念已深入人心。人们渐渐认识到&#xff0c;一个舒适的床垫不仅仅是睡眠的工具&#xff0c;更是健康的守护者。很多朋友在选购床垫一掷千金&#xff0c;却找不到一款合适的床垫。康姿百德床垫是专为提升睡眠质量研发的床垫&#xff0c;成为了…

保姆级教程:从0到1搭建web自动化测试环境

之前都是在linux上安装&#xff0c;第一次在windows上配置环境&#xff0c;加上距离上次配置环境有点久了&#xff0c;竟也花了点时间。特此记录下保姆级教程&#xff0c;给初学者一个有效的参考&#xff01; 一. 环境搭建 工具清单 工具工具名版本Java开发工具包JDK1.8浏览…

面试手写第五期

文章目录 一. 实现一个函数用来对 URL 的 querystring 进行编码二. 如何实现一个数组洗牌函数 shuffle三. 异步加法的几种方式四. 实现trim函数五. 求多个数组的交集六. 手写实现render函数七. 驼峰转- -转驼峰八. instanceof实现九. 组合问题十. 字符串分组 一. 实现一个函数用…

Linux 命令 —— top

Linux 命令 —— top 相对于 ps 是选取一个时间点的进程状态&#xff0c;top 则可以持续检测进程运行的状态。使用方式如下&#xff1a; 用法&#xff1a; top [-d secs] | [-p pid] 选项与参数&#xff1a; -d secs&#xff1a;整个进程界面更新 secs 秒。默认是 5 5 5 秒。…

用函数求最小公倍数和最大公约数(c++题解)

题目描述 输入两个正整数m和n&#xff0c;求其最大公约数和最小公倍数。 提示&#xff0c;求最大公约数用一个函数实现。本题求最大公约数必须用高效算法&#xff0c;如辗转相除法&#xff0c;朴素算法要超时。 输入格式 第1行&#xff1a;两个非整数&#xff0c;值在0&…

C++之平衡二叉搜索树查找

个人主页&#xff1a;[PingdiGuo_guo] 收录专栏&#xff1a;[C干货专栏] 大家好&#xff0c;我是PingdiGuo&#xff0c;今天我们来学习平衡二叉搜索树查找。 目录 1.什么是二叉树 2.什么是二叉搜索树 3.什么是平衡二叉搜索树查找 4.如何使用平衡二叉搜索树查找 5.平衡二叉…