05_G1垃圾收集器

G1垃圾收集器简介

垃圾优先 Garbage-First(G1)垃圾收集器面向多处理器机器,适用于大内存场景。它尝试在无需太多配置的情况下实现垃圾收集暂停时间目标,并同时实现高吞吐量。G1旨在通过适用于当前目标应用和环境的功能,提供最佳的延迟和吞吐量平衡,这些功能包括:

  • - 堆大小高达数十 GB甚至更大,超过50% 的Java堆内存用于存储活动数据
  • - 对象分配和晋升的速率会随时间显著变化。
  • - 堆中存在大量碎片化。
  • - 具有可预测的暂停时间目标,不超过几百毫秒,避免长时间的垃圾回收暂停。

G1 在应用程序运行时同时执行部分工作,它会利用处理器资源来缩短收集暂停,这一点最为显著。这主要体现在应用程序运行时会有一个或多个垃圾回收线程处于活动状态。因此,与吞吐量收集器相比,尽管使用 G1 收集器时垃圾回收暂停通常要短得多,但应用程序的吞吐量也往往稍微降低。

G1 收集器通过后面讲到的几种方式实现高性能并努力实现暂停时间目标。

应用程序开启G1

垃圾优先(Garbage-First)垃圾收集器是默认的收集器,因此通常无需执行任何额外操作。你可以在命令行上显式启用它,提供参数 -XX:+UseG1GC。

基本概念

G1是一种分代、增量、并行、大部分并发、停顿式以及疏散式的垃圾收集器,它在每次STW暂停中监视暂停时间目标。类似于其他垃圾收集器,G1将堆分成(虚拟的)年轻代和老年代。空间回收工作主要集中在年轻代上,因为在该代进行空间回收是最为高效的,偶尔也会在老年代进行空间回收。

一些操作总是在STW暂停中执行,以改进吞吐量。而其他需要耗费更多时间的操作(如全堆操作,例如全局标记)则可以并行且与应用程序同时进行。为了缩短用于空间回收的停顿时间,G1采用了分步递增和并行的方式来执行空间回收。G1通过跟踪先前的应用程序行为和垃圾收集暂停信息来建立相关成本模型,以实现可预测性。它利用这些信息来确定在暂停期间执行的工作量大小。例如,G1首先在最为高效的区域(即大部分填充有效垃圾的区域)进行空间回收,这也是其名称来源之处。

G1主要通过 evacuate 疏散来回收空间:发现于选定内存区域中的存活对象被复制到新内存区域中,并在此过程中进行压缩。在完成疏散后,先前被存活对象占据的空间将被应用程序重新使用进行分配(通过写入新数据覆盖来替代删除操作)。

垃圾优先(Garbage-First)收集器不是实时垃圾收集器。它尝试在较长时间内以很高概率满足设定的暂停时间目标,但对于特定暂停,并不总是能绝对确定地满足这一目标。

堆的布局结构

G1将堆分成一组大小相等的堆区域,每个区域都是一段虚拟内存的连续范围,如图7-1所示。一个区域是内存分配和内存回收的单位。在任何给定时间,这些区域中的每一个可以是空的(浅灰色),或者被分配给特定的年代,年轻代或老年代。当内存请求到来时,内存管理器会分配空闲区域,并将其分配给一个年代,然后将它们作为可用空间返回给应用程序进行自我分配。

图7-1 G1垃圾收集器堆布局

年轻代包括伊甸园区域(红色)和幸存者区域(带有"S"的红色)。这些区域提供了与其他收集器中相应连续空间相同的功能,不同之处在于在G1中,这些区域通常以非连续的模式布置在内存中。老年代包括老年代区域(浅蓝色)。老年代区域可能是巨大对象所占用的大型区域(带有"H"的浅蓝色)。

应用程序总是首先分配给年轻代,也就是伊甸园区域,除了那些被直接分配到老年代的巨大对象。

垃圾收集器的回收周期

在高层级上,G1收集器在两个阶段之间进行交替。年轻代阶段包含垃圾收集,逐渐填充老年代中当前可用内存中的对象。空间回收阶段是G1在处理年轻代的同时逐步回收老年代中的空间。然后循环重新开始,进行下一个年轻代阶段。

图7-2概述了这一循环及可能发生的垃圾收集暂停顺序的示例:

图7-2垃圾收集周期概述

以下是G1垃圾收集循环的各个阶段和阶段间转换的详细描述:

1.年轻代阶段:这一阶段以少量普通的年轻代收集开始,将对象提升至老年代。当老年代占用达到一定阈值(初始堆占用率阈值)时,年轻代阶段和空间回收阶段之间的转换开始。此时,G1安排了一个并发初始 Young 收集(Concurrent Start young collection),而不是进行普通的年轻代收集。

2.并发初始化:这种类型的收集启动标记过程,并进行普通的年轻代收集。并发标记确定所有当前可达(存活)的老年代区域中需要在接下来的空间回收阶段中保留。在标记过程尚未完全完成时,可能会出现普通的年轻代收集。标记最终通过两个特殊的STW暂停完成:重新标记(Remark)和清理(Cleanup)。

3.重新标记:这个暂停最终化了标记本身,执行引用处理和类卸载,回收完全空的区域,并清理内部数据结构。在重新标记和清理之间,G1计算信息,以便稍后能够同时在选定的老年代区域中回收自由空间,在清理暂停中将会得以最终完成。

4.清理:这一暂停确定是否确实需要进行空间回收阶段。如果空间回收随后进行,年轻代阶段将以Prepare Mixed young collection 完成。

5.空间回收阶段:这一阶段包括多个普通 Young 收集,在这些普通 Young 收集之外,还会疏散掉一些存活对象所在的老年代区域。这些收集也被称为混合(Mixed)收集。当G1确定疏散更多老年代区域不会带来足够值得努力的自由空间时,空间回收阶段结束。

在进行空间回收后,垃圾回收循环重新开始进入另一个年轻代阶段。作为备用方案,在应用程序获取存活信息时如果出现内存耗尽情况,则G1将执行类似其他垃圾收集器那样的就地停顿式全堆压缩(Full GC)。

垃圾收集的暂停和集合

G1在停顿式暂停中执行垃圾收集和空间回收。通常,活动对象从源区域复制到堆中的一个或多个目标区域,同时会调整对这些移动对象的现有引用。

对于非巨大(non-humongous)区域,对象的目标区域根据该对象的源区域确定:

1.年轻代中的对象(伊甸园和幸存者区域)根据它们的年龄被复制到幸存者或老年代中。
2.老年代中的对象被复制到其他老年代区域中。

巨大(humongous)区域中的对象则被单独处理。G1只会确定它们的存活状态,如果它们是非存活对象,则回收它们占用的空间。G1只会在极少数情况下通过非常耗时的手段来移动巨大对象。

记忆集(Remembered Set)

为了疏散收集集合,G1管理了一个记忆集(remembered set):这是指包含指向收集集合的引用的收集之外的位置的集合。当收集集合中的对象在垃圾回收过程中移动时,来自收集之外对该对象的其他引用需要被修改,指向该对象的新位置。

记忆集条目表示用于节省内存的大致位置:通常,彼此靠近的引用会指向彼此附近的对象。G1在逻辑上将堆分成了卡片(card),默认情况下每个卡片大小为512字节。记忆集条目是这些卡片的压缩索引。

初始化时,G1基于每个区域进行管理记忆集:每个区域都包含一个区域级别的记忆集,即潜在具有对该区域引用关系的位置的集合。在垃圾回收过程中,整个收集设置的记忆集是从这些单独记忆容器生成出来。

记忆容器是通过懒加载创建的:在重新标记和清理暂停阶段之间,G1重新构建所有收集候选区域的记忆容器。除此之外,默认情况下对于 年期代 G1总是在每次回收时都进行更新;而对于一些巨型对象也是一样的。

收集集合(Collection Set)

收集集合是要从中回收空间的源区域的集合。根据垃圾回收的类型,收集集合包括不同类型的区域:

  • 在仅年轻代(Young-Only)阶段,收集集合仅包括年轻代中的区域以及可能需要回收的巨大对象所在的巨大区域。
  • 在空间回收(Space-Reclamation)阶段,收集集合包括年轻代中的区域、可能需要回收的巨大对象所在的巨大区域,以及来自收集集合候选区域集合中一些老年代区域。

收集候选区域是在空间回收阶段极有可能被回收的区域。G1在重新标记(Remark)暂停期间根据这些区域所包含的存活数据量及它们与其他区域之间的连通性来选择这些候选区域。G1更倾向于选择具有少量存活数据而非主要为存活数据所占据的区域,并且也更倾向于选择具有较少连通性而非高连通性的区域,因为对于这些更“高效”的区域进行回收所需的工作量较小。G1会将那些无法为释放内存贡献太多空间利益的候选区域剔除。这包括那些可以回收空间少于当前堆大小的-XX:G1HeapWastePercent百分比值设定值。G1将不会在这次空间回收阶段中对这些区域进行回收。

在重新标记与清理暂停期间,G1继续准备好这些被后续进行回收操作所需用到的工作,在清理暂停期结束时对它们按效率进行排序。同时,在随后进行混合(Mixed)回收时,会优先选择那些更高效、需要更少时间进行回收并且包含更多可用空闲空间的区域进行回收操作。

垃圾收集过程

垃圾回收包括四个阶段:

1.预清空收集集合(Pre Evacuate Collection Set)阶段:执行一些垃圾回收的准备工作,包括与mutator线程断开TLABs的连接,根据Java堆大小选择此次回收的收集集合,并进行其他一些小的准备工作。

2.合并堆根(Merge Heap Roots):G1从收集集合区域创建单一统一的记忆集,以便后续更容易并行处理。这样可以消除单独记忆集中的许多重复项,否则这些重复项将需要在后续以更昂贵的方式进行过滤。

3.清空收集集合(Evacuate Collection Set):主要工作发生在这个阶段。G1开始移动对象,从根引用开始。根引用是从收集集合外部来的引用,可以是来自某些VM内部数据结构(外部根)、代码(代码根),或者是来自Java堆剩余部分(堆根)。对于所有的根引用,G1将被引用到收集集合中的对象复制到它们应该移动到的目标位置,并处理它们对于收集集合中对象的引用作为新的根引用,直到没有更多的根引用。

  可以使用`-Xlog:gc+phases=debug`日志记录观察每个阶段的时间信息,分别记录在Ext Root Scanning、Code Root Scan、Scan Heap Roots和Object Copy子阶段。

4.后清空收集集合(Post Evacuate Collection Set):包括参考处理和为接下来mutator阶段做准备等清理工作。

这些阶段对应着使用`-Xlog:gc+phases=info`日志记录打印出来的信息。

G1的详细设计

堆的大小

G1在调整Java堆大小时遵循标准规则,使用以下参数进行调整:
- -XX:InitialHeapSize作为初始Java堆大小
- -XX:MaxHeapSize作为最大Java堆大小
- -XX:MinHeapFreeRatio用于确定最小的空闲内存百分比
- -XX:MaxHeapFreeRatio用于确定调整后的最大空闲内存百分比

G1收集器在重新标记(Remark)和完全垃圾回收(Full GC)暂停期间考虑根据这些选项调整Java堆的大小。这个过程可能会向操作系统释放内存或者从操作系统分配内存。

堆扩展发生在收集暂停期间,而内存释放发生在应用程序并发暂停之后。

周期性的垃圾回收

如果由于应用程序的不活动导致长时间没有垃圾回收,虚拟机可能会长时间保留大量未使用的内存,这些内存本可以用在其他地方。为了避免这种情况,可以使用`-XX:G1PeriodicGCInterval`选项强制G1定期进行垃圾回收。该选项确定了G1考虑执行垃圾回收的最小时间间隔(以毫秒为单位)。如果距离上次垃圾回收暂停已经过去这么长时间,并且没有并发循环在进行中,G1会触发额外的垃圾回收,并可能产生以下效果:

在仅年轻代阶段:G1启动并发标记,使用并发启动暂停;或者如果指定了`-XX:-G1PeriodicGCInvokesConcurrent`选项,则会触发一次完全垃圾回收。
在空间回收阶段:G1会继续空间回收阶段,并触发适合当前进度的垃圾回收暂停类型。

`-XX:G1PeriodicGCSystemLoadThreshold`选项可以用来确定是否触发垃圾回收:如果JVM主机系统(例如容器)上getloadavg()调用返回的平均一分钟系统负载值高于此阈值,则不会运行定期的垃圾回收。

初始化堆的容量(IHOP)

初始堆占用百分比  Initiating Heap Occupancy Percent(IHOP)是触发并发启动收集的阈值,它被定义为老年代大小的百分比。

G1默认情况下通过观察标记所需的时间以及在标记周期中老年代通常分配了多少内存来自动确定最佳的IHOP。这个功能称为自适应IHOP。如果此功能处于活动状态,那么选项`-XX:InitiatingHeapOccupancyPercent`在没有足够观察来进行对初始堆占用百分比阈值进行良好预测时,该初始值作为当前老年代大小的百分比。关闭G1的这种行为可以使用选项`-XX:-G1UseAdaptiveIHOP`。在这种情况下,`-XX:InitiatingHeapOccupancyPercent`的值始终确定此阈值。

在内部,自适应IHOP试图设置初始堆占用百分比,以便空间回收阶段的第一次混合垃圾回收在老年代占用达到当前最大老年代大小减去`-XX:G1HeapReservePercent`作为额外缓冲区时开始。

标注

G1标记使用的算法称为Snapshot-At-The-Beginning(SATB)。它在初始标记暂停时对堆进行虚拟快照,这意味着在标记开始时存活的所有对象在其余的标记过程中都被认为是存活的。这意味着在标记过程中变为死亡(无法访问)的对象仍然被视为存活,供空间回收之用(有一些例外)。这可能会导致与其他收集器相比,错误地保留一些额外内存。然而,SATB在重新标记暂停期间可能提供更好的延迟性。被过度保守地考虑为存活的对象在下一个阶段的标记过程中将会被回收。

堆内的活跃对象过多处理

当应用程序保持了大量内存活跃,以至于无法找到足够的空间进行复制时,就会发生疏散失败(Evacuation Failure)。疏散失败意味着G1尝试通过将已经移动的对象保留在其新位置,而不是复制尚未移动的对象,并仅调整对象之间的引用来完成当前的垃圾回收。疏散失败可能会带来一些额外开销,但通常应该与其他年轻代收集一样快速。在疏散失败之后,G1将恢复应用程序运行,不会采取其他措施。G1假设疏散失败发生在垃圾回收结束之前;也就是说,大多数对象已经移动,并且有足够的剩余空间可以继续运行应用程序,直到标记完成并开始空间回收。

如果这个假设不成立,那么G1最终会安排进行一次完全垃圾回收(Full GC)。这种类型的收集对整个堆进行原地压缩,可能非常耗时。

巨型对象

巨型对象(Humongous objects)是指大小大于或等于半个区域的对象。当前的区域大小是根据G1 GC 的默认值,中描述的方式确定的,除非使用`-XX:G1HeapRegionSize`选项进行设置。

这些巨型对象有时会以特殊方式处理:

  • - 每个巨型对象都会在老年代的一系列连续区域进行分配。对象本身的起始位置始终位于该序列中第一个区域的起始位置。在该序列中最后一个区域中剩余的空间,在整个对象被回收之前都无法用于分配。
  • - 通常,巨型对象只能在清理暂停期间(即标记结束时)或者在进行了FGC后才能被回收。然而,对于例如布尔值、各种整数和浮点值等原始类型数组,有一项特殊规定。G1会尝试性的回收巨型对象,如果它们在任何垃圾回收暂停期间没有被许多对象引用。此行为默认启用,但您可以使用`-XX:G1EagerReclaimHumongousObjects`选项进行禁用。
  • - 分配巨型对象可能会导致垃圾回收暂停过早发生。G1会在每次巨型对象分配时检查初始堆占用阈值,并且如果当前占用超过该阈值,则可能立即强制进行YGC。
  • - 巨型对象只有在第一次FGC失败,进行第二次FGC中的阶段中,才会移动。这个过程非常缓慢。由于包含巨型对象末端的堆区域中存在无法使用的空间,因此仍然有可能导致G1以内存不足 (oom)退出虚拟机。

G1的默认配置

以下是G1的一些默认配置,无需显示的配置就可使用

Option and Default ValueDescription

-XX:MaxGCPauseMillis=200

最大暂停时间

-XX:GCPauseTimeInterval=<ergo>

最大暂停时间间隔的目标。默认情况下,G1不设定任何目标,允许 G1在极端情况下连续执行垃圾收集。

-XX:ParallelGCThreads=<ergo>

垃圾回收暂停期间用于并行工作的最大线程数,取决于运行虚拟机的计算机上可用线程数量。计算方法如下:如果可用于进程的 CPU 线程数少于或等于 8,则使用该数量。否则,将大于 8 的线程数的五分之八添加到最终线程数中。

在每次暂停开始时,使用的最大线程数还受到最大总堆大小的限制:G1 不会使用超过每 -XX:HeapSizePerGCThread 个的 Java 堆容量一倍的线程。

-XX:ConcGCThreads=<ergo> 

并行工作的最大线程数。默认情况下,此值为-XX:ParallelGCThreads除以 4。

-XX:+G1UseAdaptiveIHOP

-XX:InitiatingHeapOccupancyPercent=45

控制初始堆占用情况的默认值表明,自适应确定该值已经开启,并且在最初的几个收集周期中,G1 将使用老年代的 45% 作为标记启动阈值。

-XX:G1HeapRegionSize=<ergo> 

堆区域的大小。默认值基于最大堆大小,并且计算为大约 2048 个区域,最大符合人体工程学确定值为 32 MB。用户给定的大小必须是 2 的幂,并且有效的取值范围是从 1 到 512 MB。

-XX:G1NewSizePercent=5

-XX:G1MaxNewSizePercent=60

“young generation”的总大小是根据当前正在使用的Java堆大小按百分比而变化在这两个值之间。

-XX:G1HeapWastePercent=5

允许在收集集合候选项中未回收的空间百分比。如果收集集合候选项中的可用空间低于这个值,G1将停止空间回收阶段。

-XX:G1MixedGCCountTarget=8

空间回收阶段的预期长度以收集数量

-XX:G1MixedGCLiveThresholdPercent=85

在空间回收阶段中,老年代区域中活跃对象占用比例高于此百分比的区域将不会被收集。

注意: < ergo > 意味着实际值是根据环境的人机工程学确定的。

与其他收集器的比较

这是 G1 与其他收集器主要差异的摘要:

  • 并行 GC 只能作为一个整体对老年代进行压缩和回收空间。而 G1 则将这项工作分配到多个更短的收集中,大大缩短了暂停时间,但有可能牺牲吞吐量。
  • G1 在部分老年代空间回收时是并发进行的。
  • 由于其并发特性,G1 的开销可能会比上述收集器更高,从而影响吞吐量。
  • ZGC 旨在在牺牲一定吞吐量的情况下显著减少暂停时间。

由于其工作方式,G1 具有一些机制来提高垃圾回收效率:

  • G1 可以在任何垃圾回收过程中回收老年代中一些完全空的大区域。这可以避免许很多本来不必要的垃圾回收,并且在不费力气的情况下释放大量空间。
  • G1 还可以选择性地尝试并发地对 Java 堆中重复的字符串进行去重。
  • 从老年代回收空的大对象始终是开启的。你可以使用选项 -XX:-G1EagerReclaimHumongousObjects 来禁用此特性。字符串去重默认情况下是禁用的,你可以使用选项 -XX:+G1EnableStringDeduplication 来启用它。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

go mod

常用命令 初始化模块 go mod init 模块名下载 go.mod 文件中指明的所有依赖 go mod download github.com/gin-gonic/ginv1.9.(依赖路径)依赖对其&#xff08;使引用的都是所依赖的&#xff09; go mod tidy编辑go.mod go mod edit go mod edit -require"github.com/g…

记录几种排序算法

十种常见排序算法可以分类两大类别&#xff1a;比较类排序和非比较类排序。 常见的快速排序、归并排序、堆排序以及冒泡排序等都属于比较类排序算法。比较类排序是通过比较来决定元素间的相对次序&#xff0c;其时间复杂度不能突破 O(nlogn)。在冒泡排序之类的排序中&…

数据结构---时间复杂度+空间复杂度

算法(algorithm)简单说就是解决问题的方法。方法有好坏&#xff0c;同样算法也是&#xff0c;有效率高的算法&#xff0c;也有效率低的算法。衡量算法的好坏一般从时间和空间两个维度衡量&#xff0c;也就是本文要介绍的时间复杂度和空间复杂度。有些时候&#xff0c;时间与空间…

js api part3

环境对象 环境对象&#xff1a; 指的是函数内部特殊的 变量 this &#xff0c; 它代表着当前函数运行时所处的环境 作用&#xff1a; 弄清楚this的指向&#xff0c;可以让我们代码更简洁 函数的调用方式不同&#xff0c;this 指代的对象也不同 【谁调用&#xff0c; this 就是…

springboot模块以及非springboot模块构成的多模块maven项目最佳构建方式

文章目录 背景一般的实现使用spring-boot-dependencies 更优雅的实现. 背景 有时候构建一个多模块maven项目其中某一个模块是web-service需要使用spring boot,其他模块跟spring boot 完全无关,本文总结一下在这个场景下maven项目最佳构建方式. 一般的实现 网上应该也看到过很…

智能工业相机哪家好?

一、什么是智能工业相机 在工业自动化的浪潮中&#xff0c;智能工业相机扮演着至关重要的角色。它们如同工业领域的“眼睛”&#xff0c;为生产过程提供精准的视觉监测和数据采集。然而&#xff0c;面对众多的智能工业相机品牌&#xff0c;如何选择一款真正适合的产品成为了众多…

企业开发基础--数据库

今天完成了数据库学习的全部内容&#xff0c;在事务&#xff0c;索引&#xff0c;范式中要有个人逻辑上的理解&#xff0c;也算是卡着点完成了大多数预期&#xff0c;还有一个Java游戏未完成&#xff0c;会后续补上。 之后的一周要完成34道数据库练习题以及JDBC&#xff0c;学…

88、动态规划-乘积最大子数组

思路&#xff1a; 首先使用递归来解&#xff0c;从0开始到N&#xff0c;每次都从index开始到N的求出最大值。然后再次递归index1到N的最大值&#xff0c;再求max。代码如下&#xff1a; // 方法一&#xff1a;使用递归方式找出最大乘积public static int maxProduct(int[] num…

Graph RAG:基于知识图谱的检索增强技术与优势对比

身处信息爆炸时代&#xff0c;如何从海量信息中获取准确全面的搜索结果&#xff0c;并以更直观、可读的方式呈现出来是大家期待达成的目标。传统的搜索增强技术受限于训练文本数量、质量等问题&#xff0c;对于复杂或多义词查询效果不佳&#xff0c;更无法满足 ChatGPT 等大语言…

【Linux】进程间通信 - 管道

文章目录 1. 进程间通信介绍1.1 进程间通信目的1.2 进程间通信发展1.3 进程间通信分类 2. 管道2.1 什么是管道2.2 匿名管道2.3 用 fork 来共享管道原理2.4 站在文件描述符角度 - 深入理解管道2.5 站在内核角度 - 管道本质2.6 管道读写规则2.7 管道特点 3. 命名管道3.1 匿名管道…

C语言实战项目--贪吃蛇

贪吃蛇是久负盛名的游戏之一&#xff0c;它也和俄罗斯⽅块&#xff0c;扫雷等游戏位列经典游戏的行列。在编程语言的教学中&#xff0c;我们以贪吃蛇为例&#xff0c;从设计到代码实现来提升大家的编程能⼒和逻辑能⼒。 在本篇讲解中&#xff0c;我们会看到很多陌生的知识&…

牛角源码 | 【独立版】商城盲盒源码带uniapp(H5+小程序+APP三端)全开源

前端uniapp开源代码&#xff0c;可用HBuilder工具无限发行H5、小程序和打包app&#xff0c;后端PHP开源源码&#xff0c;支持二开。 内有安装搭建教程&#xff0c;轻松部署&#xff0c;搭建即可运营&#xff0c;内置永久免费更新地址&#xff0c;后续无忧升级。 下载地址&…

window 安装ai 基础环境(yolo8,训练推理等)

安装步骤: 1. python sdk 3.9以上&#xff1a;选择 3.9.13, 不知道为什么 3.9.0-0a等安装pytorch 不行。 2. 显卡驱动 可以使用驱动精灵 直接安装N 卡推荐 3. 安装机器学习套件CUDA cuda 安装在PyTorch 需要根 PyTorch版本一致&#xff0c;我的 win-srv 最高支持 12.1 …

专业渗透测试 Phpsploit-Framework(PSF)框架软件小白入门教程(五)

本系列课程&#xff0c;将重点讲解Phpsploit-Framework框架软件的基础使用&#xff01; 本文章仅提供学习&#xff0c;切勿将其用于不法手段&#xff01; 继续接上一篇文章内容&#xff0c;讲述如何进行Phpsploit-Framework软件的基础使用和二次开发。 在下面的图片中&#…

星辰考古:TiDB v1.0 再回首

“ 1.0 版本只是个开始&#xff0c;是新的起点&#xff0c;愿我们一路相扶&#xff0c;不负远途。 前言 TiDB 是 PingCAP 公司自主设计、研发的开源分布式关系型数据库。 近日&#xff0c;TiDB v8.0.0 DMR 发布&#xff0c;详细发版说明戳这里&#xff1a; https://docs.pingca…

2024年Q1季度防晒霜数据分析:个性化与差异化成为破局关键

五一出游期间&#xff0c;防晒必不可少&#xff0c;尤其是随着“颜值经济”的崛起&#xff0c;防晒霜成为了许多消费者出游时的必备选择。但随着“物理防晒”、“硬防晒”等概念的推出&#xff0c;防晒霜作为“化学防晒”的代表&#xff0c;在今年Q1季度线上市场表现受到影响。…

ICode国际青少年编程竞赛- Python-1级训练场-变量入门

ICode国际青少年编程竞赛- Python-1级训练场-变量入门 1、 a 4 Dev.turnRight() Dev.step(a)2、 a 4 Spaceship.step(a) Dev.step(a)3、 a 4 Dev.step(a) Dev.turnLeft() Dev.step(a)4、 a 5 Dev.step(a) Spaceship.step(a) Dev.step(a)5、 a 3 Dev.step(a) Dev.tur…

轨道交通巡检机器人的应用范围

在现代轨道交通系统的庞大网络中&#xff0c;无数的轨道、设备和设施交织在一起&#xff0c;如同一个精密的机器在高效运转。而在这背后&#xff0c;轨道交通巡检机器人正悄然登场&#xff0c;它们如同一个个智能的守护者&#xff0c;穿梭于各个场景之中。那么&#xff0c;这些…

【LeetCode:1235. 规划兼职工作 + 动态规划 + 二分查找】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

win10安装DHCP服务--用于2台机器之间搭建简易网络来进入目标机器修改配置

前言&#xff1a; 客户多了&#xff0c;往往会出现各种突发情况。 比如一个客户现场没有DHCP&#xff0c;没有显示器&#xff0c;键盘。 你只有一台笔记本的情况下要配置目标机器的网络。要如何配置&#xff1f;&#xff1f; 这时候就可以使用这篇博客提供的方式了。 Windows…