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

Golang GC 介绍

文章目录

  • 0.前言
  • 1.发展史
  • 2.并发三色标记清除和混合写屏障
    • 2.1 三色标记
    • 2.2 并发标记问题
    • 2.3 屏障机制
      • Dijkstra 插入写屏障
      • Yuasa 删除写屏障
      • 混合写屏障
  • 3.GC 过程
  • 4.GC 触发时机
  • 5.哪里记录了对象的三色状态?
  • 6.如何观察 GC?
    • 方式1:GODEBUG=gctrace=1
    • 方式2: go tool trace
    • 方式3:debug.ReadGCStats
    • 方式4:runtime.ReadMemStats
  • 参考文献

0.前言

GC 全称 Garbage Collection,目前主流的垃圾回收算法有两类,分别是追踪式垃圾回收算法(Tracing garbage collection)和引用计数法( Reference counting )。

Golang 使用的三色标记法属于追踪式垃圾回收算法的一种。

追踪式算法的核心思想是判断一个对象是否可达,因为一旦这个对象不可达就可以立刻被 GC 回收了。

1.发展史

v1.1 标记清除法,整个过程都需要 STW。gc pause 数百 ms 级。

v1.3 标记清除法,标记过程仍需要 STW,清除过程并行化。gc pause 百 ms 级。

v1.5 并发三色标记清除和写屏障。仅在堆空间启动插入写屏障,全部扫描后需要 STW 重新扫描栈空间。gc pause 10 ms 级。

v1.8 并发三色标记清除和混合写屏障。仅在堆空间启动插入写屏障,全部扫描后不需要 STW 重新扫描栈空间。gc pause 0.5 ms 级。

混合写屏障指 Dijkstra 插入写屏障和 Yuasa 删除写屏障。

2.并发三色标记清除和混合写屏障

2.1 三色标记

三色标记算法将程序中的对象分成白色、黑色和灰色。

  • 白色对象(可能死亡):未被回收器访问到的对象。在回收开始阶段,所有对象均为白色,当回收结束后,白色对象均不可达。
  • 灰色对象(波面):已被回收器访问到的对象,但回收器需要对其中的一个或多个指针进行扫描,因为他们可能还指向白色对象。
  • 黑色对象(确定存活):已被回收器访问到的对象,其中所有字段都已被扫描,黑色对象中任何一个指针都不可能直接指向白色对象。

回收器首先将所有对象标记成白色,然后从根对象集合出发,逐步把所有可达的对象变成灰色再到黑色,最终所有的白色对象都是不可达对象,即垃圾对象。

具体实现:

  • 将所有对象标记为白色。
  • 从根节点集合出发,将第一次遍历到的节点标记为灰色放入集合列表中。
  • 遍历灰色集合,将灰色节点遍历到的白色节点标记为灰色,并把灰色节点标记为黑色。
  • 重复,上一步骤,直到灰色对象队列为空。
  • 剩下的所有白色对象都是垃圾对象。

在这里插入图片描述

根对象是垃圾回收器在标记过程最先检查的对象,包括:

  • 全局变量:程序在编译期就能确定的那些存在于程序整个生命周期的变量。
  • 执行栈:每个 goroutine 都包含自己的执行栈,这些执行栈上包含栈上的变量及指向分配的堆内存区块的指针。
  • 寄存器:寄存器的值可能表示一个指针,参与计算的这些指针可能指向某些赋值器分配的堆内存。

2.2 并发标记问题

在垃圾回收过程中,标记操作与程序的执行可以同时进行,故称为并发三色标记

并发标记可以提高程序性能,但是存在问题。

假设有三个对象,A、B 和 C,标记过程中状态如下:

在这里插入图片描述
赋值器并发地将黑色对象 C 指向了白色对象 B,并移除灰色对象 A 对白色对象 B 的引用。

在这里插入图片描述
然后继续扫描灰色对象 A,那么白色对象 B 永远不会被标记为黑色对象了(回收器不会重新扫描黑色对象),进而对象 B 被误回收。

在这里插入图片描述

因为漏标记导致回收了仍在使用的对象。

垃圾回收的原则是不应出现对象的丢失(内存泄漏),也不应错误地回收还不需要回收的对象(漏标记)。如果同时满足下面两个条件会破坏回收器的正确性:

  • 条件 1: 赋值器修改对象,导致某一黑色对象引用白色对象。
  • 条件 2: 从灰色对象出发,到达白色对象且未经访问过的路径被赋值器破坏。

上面的例子就是因为同时满足了条件 1 和条件 2 导致并发标记过程漏标了仍在使用的 B 对象。

可能的解决方法: 整个过程 STW,因为这种做法对用户程序影响较大,由此引入了屏障机制。

2.3 屏障机制

使用屏障机制可以使得用户程序和三色标记过程并发执行,我们只需要达成下列任意一种三色不变性:

  • 强三色不变性:黑色对象永远不会指向白色对象。
  • 弱三色不变性:黑色对象指向的白色对象至少包含一条由灰色对象经过白色对象的可达路径。

Go 使用写屏障避免漏标记对象。

这里的写屏障是指由编译器生成的一小段代码,在 GC 时对指针操作前执行的一小段代码(和 CPU 中维护内存一致性的写屏障不太一样)。

写屏障有两种:Dijkstra 插入写屏障和 Yuasa 删除写屏障

Dijkstra 插入写屏障

Dijkstra 插入写屏障避免了前面提到的条件 1,黑色对象不会引用白色对象。

当一个对象引用另外一个对象时,将另外一个对象标记为灰色。

// Dijkstra 插入屏障
func DijkstraWritePointer(slot *unsafe.Pointer, ptr unsafe.Pointer) {shade(ptr) // 先将新下游对象 ptr 标记为灰色*slot = ptr
}

尽管 Dijkstra 插入写屏障可以实现垃圾回收和用户程序的并发执行,但是它存在两个缺点。

一方面它是一种比较保守的垃圾回收方法,在一次回收过程中可能会残留一部分对象没有回收成功,只有在下一个回收过程中才会被回收。

以下图为例,用户程序 Mutator 将对象 A 原本指向 B 对象的指针改成指向 C 对象,尽管在修改后 B 对象已经是一个垃圾对象,但是它在本轮垃圾回收过程中不会被回收。
在这里插入图片描述
另外一个缺点在于栈上的对象也是根对象,Dijkstra 插入写屏障要么在用户程序执行内存写操作时为栈对象插入写屏障,要么在一轮三色标记完成后使用 STW 重新对栈对象进行三色标记。前者会降低栈空间的响应速度,后者会暂停用户程序。

Go 1.5 选择使用 STW 重新对栈对象进行三色标记。

Yuasa 删除写屏障

Yuasa 删除写屏障避免了前面提到的条件2,防止丢失灰色对象到白色对象的可达路径。

// 黑色赋值器 Yuasa 屏障
func YuasaWritePointer(slot *unsafe.Pointer, ptr unsafe.Pointer) {shade(*slot) // 先将旧下游对象 slot 标记为灰色*slot = ptr
}

为了防止丢失从灰色对象到白色对象的路径,在 ptr 被赋值到 *slot 前,先将 *slot 标记为灰色。一句话解释就是当删除对象 A 指向对象 B 的指针时,将被删除的对象 B 标记为灰色。

下图简单绘制了 Yuasa 删除写屏障是如何保证用户程序 Mutator 和垃圾回收器 Collector 的并发执行的:

  • 第二步中 Mutator 将对象 A 原本指向对象 B 的指针指向 C,由于对象B本身就是灰色的,因此不需要对它重新着色。
  • 第三步中 Mutator 删除了对象 B 指向对象 C 的指针,删除写屏障将下游对象 C 标记为灰色。
    在这里插入图片描述
    Yuasa 删除写屏障和 Dijkstra 插入写屏障相比优点在于不需要在一轮三色标记后对栈空间上的对象进行重新扫描。缺点在于Collector 会悲观地认为所有被删除的对象都可能被黑色对象引用,所以将被删除的对象置灰。

混合写屏障

在 Go 1.8 引入混合写屏障(Hybrid Write Barrier)之前,由于 GC Root 对象包括了栈对象,如果运行时在所有 GC Root 对象上开启插入写屏障意味着需要在数量庞大的 Goroutine 的栈上都开启 Dijkstra 写屏障从而严重影响用户程序的性能。

之前的做法是标记阶段结束后暂停整个程序,对栈上对象重新进行三色标记。如果 Goroutine 较多的话,对栈对象 re-scan 这一步需要耗费 10~100 ms。

Go 1.8 为了减少标记终止阶段对栈对象的重扫成本,将 Dijkstra 插入写屏障和 Yuasa 删除写屏障进行混合,形成混合写屏障。

// 混合写屏障
func HybridWritePointerSimple(slot *unsafe.Pointer, ptr unsafe.Pointer) {shade(*slot)shade(ptr)*slot = ptr
}

注意:混合写屏障也是仅在堆空间启动的,防止降低栈空间的运行效率。

混合写屏障逻辑如下:

  • GC 开始时将栈上所有对象标记为黑色,无须 STW
  • GC 期间在栈上创建的新对象均标记为黑色
  • 将被删除的下游对象标记为灰色
  • 将被添加的下游对象标记为灰色

3.GC 过程

Golang GC 分为四个阶段:清除终止、标记、标记终止和清除。

(1)清除终止(Sweep Termination)

  • 暂停程序,所有处理器在这时会进入安全点(Safe point)。
  • 如果当前 GC 是强制触发的,还需要处理未被清理的内存管理单元。

(2)标记(Mark)

  • 将状态切换至_GCmark、开启写屏障、用户程序协助(Mutator Assists)并将根对象入队。
  • 恢复执行程序,标记进程和用于协助的用户程序会开始并发标记内存中的对象,写屏障会将被覆盖的指针和新指针都标记成灰色,而所有新创建的对象都会被直接标记成黑色。
  • 开始扫描根对象,包括所有 Goroutine 的栈、全局对象以及不在堆中的运行时数据结构,扫描 Goroutine 栈期间会暂停当前处理器。
  • 依次处理灰色队列中的对象,将对象标记成黑色并将它们指向的对象标记成灰色。
  • 使用分布式的终止算法检查剩余的工作,发现标记阶段完成后进入标记终止阶段。

(3)标记终止(Mark Termination)

  • 暂停程序,将状态切换至_GCmarktermination并关闭辅助标记的用户程序。
  • 清理处理器上的线程缓存。

(4)清除(Sweep)

  • 将状态切换至_GCoff,关闭混合写屏障。
  • 恢复用户程序,所有新创建的对象标记为白色。
  • 后台并发清理所有内存管理单元 span,当 Goroutine 申请新的内存管理单元时就会触发清除。

具体而言,各个阶段的触发函数分别为:

在这里插入图片描述

在 GC 过程中会有两种后台任务(G),包括标记任务和清除任务。可以同时执行的标记任务约是 P 数量的四分之一,即 Go 所说的 25% CPU 用于 GC 的依据。清理除任务会在程序启动后运行,清除阶段时被唤醒。

4.GC 触发时机

触发 GC 的方式有两种:手动触发和自动触发。

手动触发调用runtime.GC()函数可以强制触发 GC,该方法在调用时会阻塞调用方直到 GC 完成。在 GC 期间也可能会通过 STW 暂停整个程序。

自动触发有两种:

  • 条件触发:当新分配的内存达到上次 GC 结束时存活对象占用内存的某个比例时触发 GC,该比例可以通过环境变量GOGC调整,默认值为 100,即新增 100% 的堆内存会触发 GC。
  • 定时触发。使用系统监控协程 sysmon,当超过一段时间(由runtime.forcegcperiod变量控制,默认两分钟)没有产生任何 GC 时,强制触发 GC。

运行时会通过如下所示的runtime.gcTrigger.test方法决定是否需要触发 GC。

// test reports whether the trigger condition is satisfied, meaning
// that the exit condition for the _GCoff phase has been met. The exit
// condition should be tested when allocating.
func (t gcTrigger) test() bool {if !memstats.enablegc || panicking.Load() != 0 || gcphase != _GCoff {return false}switch t.kind {case gcTriggerHeap:// Non-atomic access to gcController.heapLive for performance. If// we are going to trigger on this, this thread just// atomically wrote gcController.heapLive anyway and we'll see our// own write.trigger, _ := gcController.trigger()return gcController.heapLive.Load() >= triggercase gcTriggerTime:if gcController.gcPercent.Load() < 0 {return false}lastgc := int64(atomic.Load64(&memstats.last_gc_nanotime))return lastgc != 0 && t.now-lastgc > forcegcperiodcase gcTriggerCycle:// t.n > work.cycles, but accounting for wraparound.return int32(t.n-work.cycles.Load()) > 0}return true
}

满足触发 GC 的基本条件:允许垃圾收集、程序没有崩溃并且 GC 处于清除阶段,即 GC 状态能为_GCoff

// 允许垃圾回收
memstats.enablegc
// 程序没有 panic
panicking == 0
// 处于 _Gcoff 阶段
gcphase == _GCoff

对应的触发时机包括:

// 堆内存达到一定阈值
gcTriggerHeap
// 距离上一次垃圾回收超过一定时间,间隔由 runtime.forcegcperiod 变量控制,默认为 2 分钟
gcTriggerTime
// 如果当前没有启动 GC 则开始新一轮的 GC。手动调用 runtime.GC() 函数会走到该分支
gcTriggerCycle

5.哪里记录了对象的三色状态?

并没有真正的三个集合来分别装三色对象。

Go 的对象分配在 span 中,span 里有一个字段是 gcmarkBits。标记阶段里面每个 bit 代表一个 slot 已被标记。

白色对象 bit 为 0,灰色或黑色为 1。
在这里插入图片描述
每个 P(Processor) 都有 wbBuf 和 gcWork 以及全局的 workbuf 标记队列。队列中的指针为灰色对象,表示已标记待扫描。

从队列中出来并把其引用对象入队的为黑色对象,表示已标记已扫描。

在这里插入图片描述

6.如何观察 GC?

以下面的程序为例,使用四种不同的方式来介绍如何观察 GC。

package mainfunc allocate() {_ = make([]byte, 1<<20)
}func main() {for n := 1; n < 1000; n++ {allocate()}
}

方式1:GODEBUG=gctrace=1

设置环境变量 GODEBUG=gctrace=1,执行程序时可以看到 GC 日志。

go build -o main
GODEBUG=gctrace=1 ./maingc 1 @0.000s 2%: 0.009+0.23+0.004 ms clock, 0.11+0.083/0.019/0.14+0.049 ms cpu, 4->6->2 MB, 5 MB goal, 12 P
scvg: 8 KB released
scvg: inuse: 3, idle: 60, sys: 63, released: 57, consumed: 6 (MB)
gc 2 @0.001s 2%: 0.018+1.1+0.029 ms clock, 0.22+0.047/0.074/0.048+0.34 ms cpu, 4->7->3 MB, 5 MB goal, 12 P
scvg: inuse: 3, idle: 60, sys: 63, released: 56, consumed: 7 (MB)
gc 3 @0.003s 2%: 0.018+0.59+0.011 ms clock, 0.22+0.073/0.008/0.042+0.13 ms cpu, 5->6->1 MB, 6 MB goal, 12 P
scvg: 8 KB released
scvg: inuse: 2, idle: 61, sys: 63, released: 56, consumed: 7 (MB)
gc 4 @0.003s 4%: 0.019+0.70+0.054 ms clock, 0.23+0.051/0.047/0.085+0.65 ms cpu, 4->6->2 MB, 5 MB goal, 12 P
scvg: 8 KB released
scvg: inuse: 3, idle: 60, sys: 63, released: 56, consumed: 7 (MB)
scvg: 8 KB released
scvg: inuse: 4, idle: 59, sys: 63, released: 56, consumed: 7 (MB)
gc 5 @0.004s 12%: 0.021+0.26+0.49 ms clock, 0.26+0.046/0.037/0.11+5.8 ms cpu, 4->7->3 MB, 5 MB goal, 12 P
scvg: inuse: 5, idle: 58, sys: 63, released: 56, consumed: 7 (MB)
gc 6 @0.005s 12%: 0.020+0.17+0.004 ms clock, 0.25+0.080/0.070/0.053+0.051 ms cpu, 5->6->1 MB, 6 MB goal, 12 P
scvg: 8 KB released
scvg: inuse: 1, idle: 62, sys: 63, released: 56, consumed: 7 (MB)

在这个日志中可以观察到两类不同的信息:

gc 1 @0.000s 2%: 0.009+0.23+0.004 ms clock, 0.11+0.083/0.019/0.14+0.049 ms cpu, 4->6->2 MB, 5 MB goal, 12 P
gc 2 @0.001s 2%: 0.018+1.1+0.029 ms clock, 0.22+0.047/0.074/0.048+0.34 ms cpu, 4->7->3 MB, 5 MB goal, 12 P
...

以及:

scvg: 8 KB released
scvg: inuse: 3, idle: 60, sys: 63, released: 57, consumed: 6 (MB)
scvg: inuse: 3, idle: 60, sys: 63, released: 56, consumed: 7 (MB)
...

含义如下表所示:

字段含义
gc 2第二个 GC 周期
0.001程序开始后的 0.001 秒
2%该 GC 周期中 CPU 的使用率
0.018标记开始时, STW 所花费的时间(wall clock)
1.1标记过程中,并发标记所花费的时间(wall clock)
0.029标记终止时, STW 所花费的时间(wall clock)
0.22标记开始时, STW 所花费的时间(cpu time)
0.047标记过程中,标记辅助所花费的时间(cpu time)
0.074标记过程中,并发标记所花费的时间(cpu time)
0.048标记过程中,GC 空闲的时间(cpu time)
0.34标记终止时, STW 所花费的时间(cpu time)
4标记开始时,堆的大小的实际值
7标记结束时,堆的大小的实际值
3标记结束时,标记为存活的对象大小
5标记结束时,堆的大小的预测值
12P 的数量

wall clock 是指开始执行到完成所经历的实际时间,包括其他程序和本程序所消耗的时间; cpu time 是指特定程序使用 CPU 的时间。

wall clock < cpu time: 充分利用多核
wall clock ≈ cpu time: 未并行执行
wall clock > cpu time: 多核优势不明显

对于运行时向操作系统申请内存产生的垃圾回收(向操作系统归还多余的内存):

scvg: 8 KB released
scvg: inuse: 3, idle: 60, sys: 63, released: 57, consumed: 6 (MB)

含义由下表所示:

字段含义
8 KB released向操作系统归还了 8 KB 内存
3已经分配给用户代码、正在使用的总内存大小 (MB)
60空闲以及等待归还给操作系统的总内存大小(MB)
63通知操作系统中保留的内存大小(MB)
57已经归还给操作系统的(或者说还未正式申请)的内存大小(MB)
6已经从操作系统中申请的内存大小(MB)

方式2: go tool trace

go tool trace 的主要功能是将统计而来的信息以一种可视化的方式展示给用户。要使用此工具,可以通过调用 trace API:

package mainfunc main() {f, _ := os.Create("trace.out")defer f.Close()trace.Start(f)defer trace.Stop()(...)
}

并通过如下命令启动可视化界面。

go tool trace trace.out

方式3:debug.ReadGCStats

此方式可以通过代码的方式来直接实现对感兴趣指标的监控,例如我们希望每隔一秒钟监控一次 GC 的状态:

func printGCStats() {t := time.NewTicker(time.Second)s := debug.GCStats{}for {select {case <-t.C:debug.ReadGCStats(&s)fmt.Printf("gc %d last@%v, PauseTotal %v\n", s.NumGC, s.LastGC, s.PauseTotal)}}
}
func main() {go printGCStats()(...)
}

我们能够看到如下输出:

go run main.gogc 4954 last@2019-12-30 15:19:37.505575 +0100 CET, PauseTotal 29.901171ms
gc 9195 last@2019-12-30 15:19:38.50565 +0100 CET, PauseTotal 77.579622ms
gc 13502 last@2019-12-30 15:19:39.505714 +0100 CET, PauseTotal 128.022307ms
gc 17555 last@2019-12-30 15:19:40.505579 +0100 CET, PauseTotal 182.816528ms
gc 21838 last@2019-12-30 15:19:41.505595 +0100 CET, PauseTotal 246.618502ms

方式4:runtime.ReadMemStats

除了使用 debug 包提供的方法外,还可以直接通过运行时内存相关的 API 进行监控:

func printMemStats() {t := time.NewTicker(time.Second)s := runtime.MemStats{}for {select {case <-t.C:runtime.ReadMemStats(&s)fmt.Printf("gc %d last@%v, next_heap_size@%vMB\n", s.NumGC, time.Unix(int64(time.Duration(s.LastGC).Seconds()), 0), s.NextGC/(1<<20))}}
}
func main() {go printMemStats()(...)
}
go run main.gogc 4887 last@2019-12-30 15:44:56 +0100 CET, next_heap_size@4MB
gc 10049 last@2019-12-30 15:44:57 +0100 CET, next_heap_size@4MB
gc 15231 last@2019-12-30 15:44:58 +0100 CET, next_heap_size@4MB
gc 20378 last@2019-12-30 15:44:59 +0100 CET, next_heap_size@6MB

当然,后两种方式能够监控的指标很多,读者可以自行查看 debug.GCStats 和 runtime.MemStats 的字段,这里不再赘述。


参考文献

图示Golang垃圾回收机制 - 知乎
Golang垃圾回收(GC)介绍
Golang 的 goroutine 是如何实现的? - 知乎
Go 垃圾回收器指南 - 鸟窝
垃圾回收的认识 | Go 程序员面试笔试宝典
垃圾回收的基本想法 | Go 语言原本
垃圾收集器 | Go 语言设计与实现

相关文章:

Golang GC 介绍

文章目录 0.前言1.发展史2.并发三色标记清除和混合写屏障2.1 三色标记2.2 并发标记问题2.3 屏障机制Dijkstra 插入写屏障Yuasa 删除写屏障混合写屏障 3.GC 过程4.GC 触发时机5.哪里记录了对象的三色状态&#xff1f;6.如何观察 GC&#xff1f;方式1&#xff1a;GODEBUGgctrace1…...

决策树之scikit-learn

实例 from sklearn.datasets import load_iris from sklearn import tree import matplotlib.pyplot as plt# Load iris dataset iris load_iris() X, y iris.data, iris.target# Fit the classifier clf tree.DecisionTreeClassifier() clf clf.fit(X, y)# Plot the deci…...

Python爬虫之关系型数据库存储#5

关系型数据库是基于关系模型的数据库&#xff0c;而关系模型是通过二维表来保存的&#xff0c;所以它的存储方式就是行列组成的表&#xff0c;每一列是一个字段&#xff0c;每一行是一条记录。表可以看作某个实体的集合&#xff0c;而实体之间存在联系&#xff0c;这就需要表与…...

ANSI Escape Sequence 下落的方块

ANSI Escape Sequence 下落的方块 1. ANSI Escape 的用途 无意中发现 B站有人讲解&#xff0c; 完全基于终端实现俄罗斯方块。 基本想法是借助于 ANSI Escape Sequence 实现方方块的绘制、 下落动态效果等。对于只了解 ansi escape sequence 用于 log 的颜色打印的人来说&…...

Vagrant 虚拟机工具基本操作指南

Vagrant 虚拟机工具基本操作指南 ​#虚拟机 #​ ​#vargant#​ ​#ubuntu#​ ‍ 虚拟机virtualbox ,VMWare及WSL等大家都很了解了&#xff0c;那Vagrant是什么东西&#xff1f; 它是一组命令行工具&#xff0c;可以象Docker管理容器一样管理虚拟机&#xff0c;这样快速创…...

中年低端中产程序员从西安出发到海南三亚低成本吃喝万里行:西安-南宁-湛江-雷州-徐闻-博鳌-陵水-三亚-重庆-西安

文章大纲 旅途规划来回行程的确定南宁 - 北海 - 湛江轮渡成为了最终最大的不确定性&#xff01;感谢神州租车气温与游玩地点总体花费 游玩过程出发时间&#xff1a;Day1-1月25日星期四&#xff0c;西安飞南宁路途中&#xff1a;Day2-1月26日星期五&#xff0c;南宁-湛江-住雷州…...

企业级Spring boot项目 配置清单

目录 一、服务基础配置 二、配置数据库数据源 三、配置缓存 四、配置日志 五、配置统一异常处理 六、配置swagger文档 七、配置用户登录模块 八、配置websocket 九、配置定时任务 十、配置文件服务器 十一、配置Nacos 十二、配置项目启动数据库默认初始化(liquibas…...

WordPress函数wptexturize的介绍及用法示例,字符串替换为HTML实体

在查看WordPress你好多莉插件时发现代码中使用了wptexturize()函数用来随机输出一句歌词&#xff0c;下面boke112百科就跟大家一起来学习一下WordPress函数wptexturize的介绍及用法示例。 WordPress函数wptexturize介绍 wptexturize( string $text, bool $reset false ): st…...

【Iceberg学习三】Reporting和Partitioning原理

Metrics Reporting Type of Reports 从 1.1.0 版本开始&#xff0c;Iceberg 支持 MetricsReporter 和 MetricsReport API。这两个 API 允许表达不同的度量报告&#xff0c;并支持一种可插拔的方式来报告这些报告。 ScanReport&#xff08;扫描报告&#xff09; 扫描报告&am…...

肯尼斯·里科《C和指针》第12章 使用结构和指针(1)链表

只恨当时学的时候没有读到这本书&#xff0c;&#xff0c;&#xff0c;&#xff0c;&#xff0c;&#xff0c; 12.1 链表 有些读者可能还不熟悉链表&#xff0c;这里对它作一简单介绍。链表(linked list)就一些包含数据的独立数据结构&#xff08;通常称为节点&#xff09;的集…...

Xray 工具笔记

Xray 官方文档 扫描单个url&#xff08;非爬虫&#xff09; 并输出文件&#xff08;不同文件类型&#xff09; .\xray.exe webscan --url 10.0.0.6:8080 --text-output result.txt --json-output result.json --html-output report.html默认启动所以内置插件 &#xff0c;指定…...

Linux环境下配置HTTP代理服务器教程

大家好&#xff0c;我是你们可爱的Linux小助手&#xff01;今天&#xff0c;我将带你们一起探索如何在Linux环境下配置一个HTTP代理服务器。请注意&#xff0c;这不是一次火箭科学的实验&#xff0c;而是一次简单而有趣的冒险。 首先&#xff0c;我们需要明确什么是HTTP代理服…...

JavaEE作业-实验三

目录 1 实验内容 2 实验要求 3 思路 4 核心代码 5 实验结果 1 实验内容 简单的线上图书交易系统的web层 2 实验要求 ①采用SpringMVC框架&#xff0c;采用REST风格 ②要求具有如下功能&#xff1a;商品分类、订单、购物车、库存 ③独立完成&#xff0c;编写实验报告 …...

K8S容器挂了后重启状态正常,但应用无法访问排查处理

K8S容器挂了后重启状态正常&#xff0c;但应用无法访问排查处理 背景&#xff1a; 应用迁移K8S后因POD OOM挂了后重启&#xff0c;集群上POD状态正常&#xff0c;但应用无法访问。 排查&#xff1a; 查看应用日志&#xff0c;是启动时调用特权账号管理系统超时&#xff0c;…...

问题:老年人心理健康维护与促进的原则为________、________、发展原则。 #媒体#知识分享

问题&#xff1a;老年人心理健康维护与促进的原则为________、________、发展原则。 参考答案如图所示...

【超高效!保护隐私的新方法】针对图像到图像(l2l)生成模型遗忘学习:超高效且不需要重新训练就能从生成模型中移除特定数据

针对图像到图像生成模型遗忘学习&#xff1a;超高效且不需要重新训练就能从生成模型中移除特定数据 提出背景如何在不重训练模型的情况下从I2I生成模型中移除特定数据&#xff1f; 超高效的机器遗忘方法子问题1: 如何在图像到图像&#xff08;I2I&#xff09;生成模型中进行高效…...

Transformer的PyTorch实现之若干问题探讨(二)

在《Transformer的PyTorch实现之若干问题探讨&#xff08;一&#xff09;》中探讨了Transformer的训练整体流程&#xff0c;本文进一步探讨Transformer训练过程中teacher forcing的实现原理。 1.Transformer中decoder的流程 在论文《Attention is all you need》中&#xff0…...

解释Python中的GIL(全局解释器锁)及其影响。描述Python中的垃圾回收机制。Python中的类变量和实例变量有什么区别

解释Python中的GIL&#xff08;全局解释器锁&#xff09;及其影响 Python中的GIL&#xff08;全局解释器锁&#xff09;是CPython解释器中的一个机制&#xff0c;用于同步线程的执行。GIL确保任何时候只有一个线程在执行Python字节码。这意味着&#xff0c;即使在多核或多处理器…...

Appium使用初体验之参数配置,简单能够运行起来

一、服务器配置 Appium Server配置与Appium Server GUI&#xff08;可视化客户端&#xff09;中的配置对应&#xff0c;尤其是二者如果不在同一台机器上&#xff0c;那么就需要配置Appium Server GUI所在机器的IP&#xff08;Appium Server GUI的HOST也需要配置本机IP&#xf…...

Java:JDK8新特性(Stream流)、File类、递归 --黑马笔记

一、JDK8新特性&#xff08;Stream流&#xff09; 接下来我们学习一个全新的知识&#xff0c;叫做Stream流&#xff08;也叫Stream API&#xff09;。它是从JDK8以后才有的一个新特性&#xff0c;是专业用于对集合或者数组进行便捷操作的。有多方便呢&#xff1f;我们用一个案…...

【Unity ShaderGraph】| 物体靠近时局部溶解,根据坐标控制溶解的位置【文末送书】

前言 【Unity ShaderGraph】| 物体靠近时局部溶解&#xff0c;根据坐标控制溶解的位置一、效果展示二、根据坐标控制溶解的位置&#xff0c;物体靠近局部溶解三、应用实例&#x1f451;评论区抽奖送书 前言 本文将使用ShaderGraph制作一个根据坐标控制溶解的位置&#xff0c;物…...

测试OpenSIPS3.4.3的lua模块

这几天测试OpenSIPS3.4.3的lua模块&#xff0c;记录如下&#xff1a; 有bug&#xff0c;但能用 但现实世界就是这样&#xff0c;总是不完美的&#xff0c;发现之后马上提了issue 下面这段代码运行报错&#xff1a; function func1(msg) xlog("ERR","…...

【机器学习】数据清洗之处理缺失点

&#x1f388;个人主页&#xff1a;甜美的江 &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;机器学习 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共同学习、交流进步…...

Linux 命令行的世界 :2.文件系统中跳转

我们需要学习的第一件事&#xff08;除了打字之外&#xff09;是如何在 Linux 文件系统中跳转。在这一章节中&#xff0c;我们将介绍以下命令&#xff1a;pwd 打印出当前工作目录名 cd 更改目录 ls 列出目录内容 Linux以分层目录结构来组织所有文件。这就意味着所有文件…...

R语言:箱线图绘制(添加平均值趋势线)

箱线图绘制 1. 写在前面2.箱线图绘制2.1 相关R包导入2.2 数据导入及格式转换2.3 ggplot绘图 1. 写在前面 今天有时间把之前使用过的一些代码和大家分享&#xff0c;其中箱线图绘制我认为是非常有用的一个部分。之前我是比较喜欢使用origin进行绘图&#xff0c;但是绘制的图不太…...

Open3D 模型切片

目录 一、算法原理1、算法过程2、主要函数二、代码实现三、结果展示1、原始数据2、切片结果本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。 一、算法原理...

KtConnect 本地连接连接K8S工具

KT Connect简介 Kt Connect &#xff08;Kubernetes Developer Tool&#xff09;是一个阿里开源、轻量级的面向 Kubernetes 用户的开发测试环境治理辅助工具。其核心是通过建立本地到集群以及集群到本地的双向通道。 1.阿里开源&#xff0c;轻量级, 2. 安装快捷简单&#xf…...

【Java万花筒】数据的安全钥匙:Java的加密与保护方法

编码的盾牌&#xff1a;Java开发人员的安全性武器库 前言 在当今数字化时代&#xff0c;保护用户数据和信息的安全已成为开发人员的首要任务。无论是在Web应用程序开发还是安全测试中&#xff0c;加密和安全性都是至关重要的。本文将介绍六个Java库和工具&#xff0c;它们为开…...

【Java多线程案例】实现阻塞队列

1. 阻塞队列简介 1.1 阻塞队列概念 阻塞队列&#xff1a;是一种特殊的队列&#xff0c;具有队列"先进先出"的特性&#xff0c;同时相较于普通队列&#xff0c;阻塞队列是线程安全的&#xff0c;并且带有阻塞功能&#xff0c;表现形式如下&#xff1a; 当队列满时&…...

【制作100个unity游戏之24】unity制作一个3D动物AI生态系统游戏3(附项目源码)

最终效果 文章目录 最终效果系列目录前言随着地面法线旋转在地形上随机生成动物不同部位颜色不同最终效果源码完结系列目录 前言 欢迎来到【制作100个Unity游戏】系列!本系列将引导您一步步学习如何使用Unity开发各种类型的游戏。在这第24篇中,我们将探索如何用unity制作一…...

home work day5

第四章 堆与拷贝构造函数 一 、程序阅读题 1、给出下面程序输出结果。 #include <iostream.h> class example {int a; public: example(int b5){ab;} void print(){aa1;cout <<a<<"";} void print()const {cout<<a<<endl;} …...

c#安全-nativeAOT

文章目录 前记AOT测试反序列化Emit 前记 JIT\AOT JIT编译器&#xff08;Just-in-Time Complier&#xff09;,AOT编译器&#xff08;Ahead-of-Time Complier&#xff09;。 AOT测试 首先编译一段普通代码 using System; using System.Runtime.InteropServices; namespace co…...

【Java】案例:检测MySQL是否存在某数据库,没有则创建

1.代码 package hello; import java.sql.*;public class CeShi {//定义基本数据static final String JDBC_DRIVER "com.mysql.cj.jdbc.Driver";static final String DB_URL "jdbc:mysql://localhost/";static final String USER "your_username&q…...

内网渗透靶场02----Weblogic反序列化+域渗透

网络拓扑&#xff1a; 攻击机&#xff1a; Kali: 192.168.111.129 Win10: 192.168.111.128 靶场基本配置&#xff1a;web服务器双网卡机器&#xff1a; 192.168.111.80&#xff08;模拟外网&#xff09;10.10.10.80&#xff08;模拟内网&#xff09;域成员机器 WIN7PC192.168.…...

[嵌入式系统-9]:C语言程序调用汇编语言程序的三种方式

目录 1. 使用函数声明和函数调用&#xff1a; 2. 使用汇编内联&#xff08;Inline Assembly&#xff09;&#xff1a; 3. 使用汇编代码文件和链接器&#xff1a; C语言程序可以调用汇编程序的方式有多种&#xff0c;下面列举了几种常见的方式&#xff1a; 1. 使用函数声明和…...

备战蓝桥杯---搜索(完结篇)

再看一道不完全是搜索的题&#xff1a; 解法1&#xff1a;贪心并查集&#xff1a; 把冲突事件从大到小排&#xff0c;判断是否两个在同一集合&#xff0c;在的话就返回&#xff0c;不在的话就合并。 下面是AC代码&#xff1a; #include<bits/stdc.h> using namespace …...

深入浅出:Golang的Crypto/SHA256库实战指南

深入浅出&#xff1a;Golang的Crypto/SHA256库实战指南 介绍crypto/sha256库概览主要功能应用场景库结构和接口实例 基础使用教程字符串哈希化文件哈希化处理大型数据 进阶使用方法增量哈希计算使用Salt增强安全性多线程哈希计算 实际案例分析案例一&#xff1a;安全用户认证系…...

Unity_ShaderGraph节点问题

Unity_ShaderGraph节点问题 Unity版本&#xff1a;Unity2023.1.19 为什么在Unity2023.1.19的Shader Graph中找不见PBR Master节点&#xff1f; 以下这个PBR Maste从何而来&#xff1f;...

Java集合 Collection接口

这里写目录标题 集合Collection接口创建一个性表增加元素删除元素修改元素判断元素遍历集合实例判断元素是否存在 集合 Java中的Collection接口是集合类的一个顶级接口&#xff0c;它定义了一些基本的操作&#xff0c;如添加、删除、查找等。Collection接口主要有以下几个常用…...

C# Task的使用

C#中的Task类是.NET框架中用于实现异步编程的核心组件之一&#xff0c;它在.NET Framework 4及更高版本以及.NET Core中广泛使用。Task对象代表一个异步操作&#xff0c;并提供了跟踪异步操作状态、获取结果和处理完成通知的方法。 Task 类提供了对异步操作的封装&#xff0c;…...

尚硅谷Ajax笔记

一天拿下 介绍二级目录三级目录 b站链接 介绍 ajax优缺点 http node.js下载配置好环境 express框架 切换到项目文件夹&#xff0c;执行下面两条命令 有报错,退出用管理员身份打开 或者再命令提示符用管理员身份打开 npm init --yes npm i express请求 <script>//引…...

【MATLAB源码-第138期】基于matlab的D2D蜂窝通信仿真,对比启发式算法,最优化算法和随机算法的性能。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 D2D蜂窝通信介绍 D2D蜂窝通信允许在同一蜂窝网络覆盖区域内的终端设备直接相互通信&#xff0c;而无需数据经过基站或网络核心部分转发。这种通信模式具有几个显著优点&#xff1a;首先&#xff0c;它可以显著降低通信延迟&…...

AcWing 第 142 场周赛 B.最有价值字符串(AcWing 5468) (Java)

AcWing 第 142 场周赛 B.最有价值字符串(AcWing 5468) (Java) 比赛链接&#xff1a;AcWing 第 142 场周赛 x题传送门&#xff1a;B.最有价值字符串 题目&#xff1a;不展示 分析&#xff1a; 题目不难&#xff0c;不过有坑&#x1f62d;。 我们可以定义一个数组记录每个字…...

滑块识别验证

滑块识别 1. 获取图片 测试网站&#xff1a;https://www.geetest.com/adaptive-captcha-demo 2. 点击滑块拼图并开始验证 # 1.打开首页 driver.get(https://www.geetest.com/adaptive-captcha-demo)# 2.点击【滑动拼图验证】 tag WebDriverWait(driver, 30, 0.5).until(la…...

每日五道java面试题之java基础篇(四)

第一题. 访问修饰符 public、private、protected、以及不写&#xff08;默认&#xff09;时的区别&#xff1f; Java 中&#xff0c;可以使⽤访问控制符来保护对类、变量、⽅法和构造⽅法的访问。Java ⽀持 4 种不同的访问权限。 default (即默认&#xff0c;什么也不写&…...

我的docker随笔43:问答平台answer部署

本文介绍开源问答社区平台Answer的容器化部署。 起因 笔者一直想搭建一个类似stack overflower这样的平台&#xff0c;自使用了Typora&#xff0c;就正式全面用MarkdownTyporagit来积累自己的个人知识库&#xff0c;但没有做到web化&#xff0c;现在也还在探索更好的方法。 无…...

17、ELK

17、ELK helm 安装 elkfk&#xff08;kafka 集群外可访问&#xff09; ES/Kibana <— Logstash <— Kafka <— Filebeat 部署顺序&#xff1a; 1、elasticsearch 2、kibana 3、kafka 4、logstash 5、filebeat kubectl create ns elkhelm3部署elkfk 1、elast…...

React+Antd+tree实现树多选功能(选中项受控+支持模糊检索)

1、先上效果 树型控件&#xff0c;选中项形成一棵新的树&#xff0c;若父选中&#xff0c;子自动选中&#xff0c;子取消&#xff0c;父不取消&#xff0c;子选中&#xff0c;所有的父节点自动取消。同时支持模糊检索&#xff0c;会检索出所有包含该内容的关联节点。 2、环境准…...

鸿蒙 WiFi 扫描流程(2)

接着上篇没有记录完的&#xff0c;我们继续梳理&#xff0c;需要上一篇做基础的请看&#xff1a;鸿蒙 WiFi 扫描流程&#xff08;1&#xff09; 上一篇我们讲到 scan_service.cpp 里面的 SingleScan 方法&#xff0c;继续这个方法往下看&#xff1a; // foundation/communicat…...

微信小程序(四十)API的封装与调用

注释很详细&#xff0c;直接上代码 上一篇 新增内容&#xff1a; 1.在单独的js文件中写js接口 2.以注册为全局wx的方式调用接口 源码&#xff1a; utils/testAPI.js const testAPI{/*** * param {*} title */simpleToast(title提示){//可传参&#xff0c;默认为‘提示’wx.sho…...