域名备案 网站名称/互联网平台有哪些
GC(Garbage Collector)垃圾回收机制及调优
简单理解GC机制
其实gc机制特别容易理解,就是物理内存的自动清理工。我们可以把内存想象成一个房间,程序运行时会在这个房间里存放各种东西,但有时候我们会忘记把不再需要的东西拿出去,这就会导致房间变得杂乱不堪。甚至会出现房间的空间不够用的情况,对应到计算机,就是OOM(out of memory, 内存再多用一点,就会爆炸)。
Go语言的GC机制会定期巡视这个房间,找出那些被遗忘的东西,并将它们清理出去,释放内存。这样,程序就能继续运行,不会因为内存不足而崩溃。
那么我们为什么要看gc机制呢,让gc自己在后台运行不好吗?其实看gc机制的主要目的就是为了内存或CPU占用率的优化,体现在两点:
- 我需要知道房间里哪些东西最占地方,看看是不能能在代码上有所优化
- 我要想要更加频繁的清理房间(减小内存占用)或更少频次的清理房间(减少CPU开销)
GC机制的原理
当然如果不想知道原理的话,直接转到第三节就好。(咳咳,其实我对细节也不是那么清楚,知道怎么用的感觉已经很不容易了>.<)
什么时候需要用到GC
其实并不是所有内存都需要GC来清理的,比如说有固定作用域的指针、地址等就无需gc,等这些对象的生命周期结束后,数据自动就会被销毁。换句人话说就是,在栈上开辟的空间会随自动释放,在堆上开辟的空间就需要gc机制来释放。如果学过C或C++就会很好理解,用make、new等操作创建的对象,都需要手动free掉,这些就是堆上开辟的内存空间。在Go语言中,就不用手动free了,这就是gc机制的作用,定期free这些手动创建(堆上)的动态内存分配的对象。
当然,专业点的话,gc是一个专门识别和清理动态内存分配的系统。如果分不清的话,可以看这个例子:
package mainimport "fmt"// 一个简单的结构体类型
type Person struct {Name stringAge int
}func main() {// 栈上的对象分配// 创建一个名为 "Alice" 年龄为 25 的 Person 对象,分配在栈上alice := Person{Name: "Alice", Age: 25}// 动态内存分配// 创建一个名为 "Bob" 年龄为 30 的 Person 对象,使用 new 函数分配在堆上bob := new(Person)bob.Name = "Bob"bob.Age = 30// 输出栈上和堆上对象的信息fmt.Printf("Stack Object: Name: %s, Age: %d\n", alice.Name, alice.Age)fmt.Printf("Heap Object: Name: %s, Age: %d\n", bob.Name, bob.Age)
}
在程序运行结束后,alice会因为生命周期结束自动free掉。但是bob仍然在堆上,等待gc机制的回收。
对于Go语言的堆栈可以仿照C++做一个简单的理解。实际上go语言的堆栈上的内存处理,确实要比上述代码中描述的要复杂很多。go语言的逃逸分析,就是专门负责堆栈上内存空间开辟的。有兴趣的话,可以右转google一下。
回收内存的方法
gc机制通过标记-清除的方式回收内存。很好理解,我想要free这块内存,起码需要知道这块内存是不是没有用了。这就是标记的作用,被标记的,就是正在使用的(in-use),未被标记的都是要被free的。(gc标记了一块地点)
这个逻辑是不是很顺,但有一个问题,为什么不把标记清除放在一起呢,我既然找到了需要free的内存,为什么不直接清除掉,还要分两个环节来做呢?因为标记需要进行全局扫描,当gc扫描到一个内存,没有被使用时,但是此时很有可能存在一个未被扫描到的指针指向了内存,如果直接free掉就会造成“悬空指针”,影响后续运行,所以必须分为两个阶段,先全局扫描,进行标记,然后陆续进行“清除”
稍微细扣一下:
标记阶段
如何确定一个内存已经没有被使用呢?gc好像有不同的方法,举个例子:引用计数(仿佛又回到了当年被八股的日子)。十分的简单,有指针指向,引用计数就加一,如果扫描到引用计数为0,房子就要没咯。这里边也涉及到一些比较专业点尔的词汇,对象、指针、对象图。对象图是由对象和指向其他对象的指针一起构成的。遍历对象图的过程称为扫描。
为了识别实时内存,GC 从程序的根部开始遍历对象图,这些指针标识程序确实正在使用的对象。当然,也不是时时刻刻都要扫描的,毕竟它也不想996。这个就涉及到频率了,后面会讲到。
还有一个很好玩的概念,因为要对“对象图”进行扫描、标记,gc会给它赋一个值,叫做活动值。trace完成后,GC 就会遍历堆中的所有内存,并使所有未标记为可供分配的内存。 这个过程称为扫掠(sweeping)(文明六直呼内行,从水下的从水下第一个生命的萌芽开始…)。
清除阶段
然后就需要扫掠了,逐个free掉,这个阶段没啥好说的,之所以单独拎出来,主要是为了标题的对称…
当然,说的有些简单了,大体上分为这两个阶段。如果细分的话,还可以分:SweepTermination、Mark、MarkTermination,还有一些标记算法比如三色标记法等等,感兴趣的可以自行查一查~
gc调优的原理和开销
GOGC 决定了 GC CPU 和内存之间的权衡。所谓的优化,也不过是在内存和CPU开销之间反复横跳,看更需要哪种资源了。gc的一些官方文档上提到:“GOGC 加倍会使堆内存开销加倍,并使 GC CPU 成本减半”。现在用数学公式来看一下二者的tradeoff
内存开销
首先,堆目标设置总堆大小的目标。超过堆目标或目标的百分比,就要执行gc了。这就是确定gc执行的时间的方案。堆目标就两部分构成:新开辟的内存和正在使用的内存(活动堆)。
# 这个是gc计算目标堆内存大小的公式,不用太纠结它的物理含义,超过这个值就需要进行gc了
Target heap memory = Live heap + (Live heap + GC roots) * GOGC / 100Total heap memory = Live heap + New heap memory
# 前两者推出:
New heap memory = (Live heap + GC roots) * GOGC / 100
-
Target heap memory(目标堆内存):这是垃圾回收器的目标,它表示希望控制整个堆的大小。这个值由Go运行时系统设置,并可以通过环境变量 GOGC 来调整。它主要影响新分配的堆内存的大小,而不是已经存在的堆内存。
-
Live heap(活动堆内存):这是当前正在使用的堆内存的大小。这包括程序中正在使用的对象和数据结构。
-
GC roots(垃圾回收根节点):这表示垃圾回收器需要考虑的根节点的数量。主要分为三部分,全局变量:程序在编译期就能确定的那些存在于程序整个生命周期的变量。执行栈:每个 goroutine 都包含自己的执行栈,这些执行栈上包含栈上的变量及指向分配的堆内存区块的指针。寄存器:寄存器的值可能表示一个指针,参与计算的这些指针可能指向某些赋值器分配的堆内存区块。
-
GOGC(Go语言的垃圾回收阈值):GOGC 是一个环境变量,表示垃圾回收器的触发阈值。当已分配的内存达到 Target heap memory 的一定百分比时,垃圾回收将被触发,默认值是100。也就是100%、
可能公式有一些绕,大概意思就是,我规定了一个目标堆内存大小的计算公式,然后,推出了新开辟的堆内存大小,只要新开辟的堆内存大小达到了New heap memory,就执行一次gc。这个新开辟的内存大小是受gc调控的。
CPU开销
来个简化版公式:
Total GC CPU cost = (Allocation rate) / (GOGC / 100) * (Cost per byte) * T
详细公式可以看:A Guide to the Go Garbage Collector
从这个简化版公式可以看出,cpu的开销适合GOGC的大小成反比的
CPU vs 内存图例
依然是上面的网站,有一个好玩的例子,应用程序总共分配 200 MiB,每次 1s分配20 MiB。它假设唯一要完成的相关 GC 工作来自活动堆,并且(不切实际地)应用程序不使用额外的内存。
- GC=100(默认情况)时
- GC=50时
- GC=-1(关闭gc)时
GC调优
同第一节所说,我们的目的有两个:
- 需要知道什么东西最占内存
- 修改gc机制的频次或阈值
查看内存,手动调优
举个例子,代码来自:go pprof
package mainimport ("fmt""net/http"_ "net/http/pprof""sync""time"
)func main() {// we need a webserver to get the pprof webservergo func() {http.ListenAndServe("localhost:6060", nil)}()fmt.Println("hello world")var wg sync.WaitGroupwg.Add(1)go leakyFunction(wg)wg.Wait()
}func leakyFunction(wg sync.WaitGroup) {defer wg.Done()s := make([]string, 3)for i := 0; i < 10000000; i++ {s = append(s, "magical pandas")if (i % 100000) == 0 {time.Sleep(500 * time.Millisecond)}}
}
leakyFunction基本上,这只是启动一个分配一堆内存的goroutine ,然后最终退出。在程序运行期间,通过以下命令查看内存的分配情况:
go tool pprof http://localhost:6060/debug/pprof/heap
然后使用top查看内存用量的前几名,如下
# go tool pprof http://localhost:6060/debug/pprof/heap
Fetching profile over HTTP from http://localhost:6060/debug/pprof/heap
Saved profile in /Users/yang/pprof/pprof.alloc_objects.alloc_space.inuse_objects.inuse_space.001.pb.gz
Type: inuse_space
Time: Oct 28, 2023 at 11:31pm (CST)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) top
Showing nodes accounting for 11715.14kB, 100% of 11715.14kB total
Showing top 10 nodes out of 24flat flat% sum% cum cum%7104.01kB 60.64% 60.64% 7104.01kB 60.64% main.leakyFunction2562.81kB 21.88% 82.52% 2562.81kB 21.88% runtime.allocm1024.01kB 8.74% 91.26% 1024.01kB 8.74% runtime.doaddtimer512.20kB 4.37% 95.63% 512.20kB 4.37% runtime.malg512.11kB 4.37% 100% 512.11kB 4.37% net/http.ListenAndServe (inline)0 0% 100% 512.11kB 4.37% main.main.func10 0% 100% 1024.01kB 8.74% runtime.bgscavenge0 0% 100% 1025.12kB 8.75% runtime.mcall0 0% 100% 1024.01kB 8.74% runtime.modtimer0 0% 100% 1537.69kB 13.13% runtime.mstart
(pprof)
当然也可以用图片:比如这样:不过需要Graphviz包,没有的话会报错,安装也很简单
apt install graphviz ## debian/ubuntu
brew install graphviz ## mac
## 然后
go tool pprof -png http://localhost:6060/debug/pprof/heap > out.png
然后就可以看到内存的分布图了
这样你就可以清晰的看到内存使用最多的函数,leakyFunction。线越粗,代表内存用量越大,不过需要注意的是,这里的信息只是你执行代码时采的点,没有办法实时反应内存用量。
找到内存耗量最大的部分,然后就可以手动对代码的做一些修改。这就极大的考验代码能力了。如果不想整,可以移步下一小节,修改gc参数,自动搞定~
当然除了看内存,还可以看cpu开销等等(这些命令我忘记从哪里粘的了,侵删),虽然官网上也有: https://pkg.go.dev/net/http/pprof。(但实在是懒,就直接粘过来了)
#所有过去内存分配的采样
go tool pprof http://127.0.0.1:6060/debug/pprof/allocs#对活动对象的内存分配进行采样
go tool pprof http://127.0.0.1:6060/debug/pprof/heap# 下载 cpu profile,默认从当前开始收集 30s 的 cpu 使用情况,需要等待 30s
go tool pprof http://127.0.0.1:6060/debug/pprof/profile
# wait 120s
go tool pprof http://127.0.0.1:6060/debug/pprof/profile?seconds=120 #导致同步原语阻塞的堆栈跟踪
go tool pprof http://127.0.0.1:8080/debug/pprof/block#所有当前goroutine的堆栈跟踪
go tool pprof http://127.0.0.1:8080/debug/pprof/goroutine#争用互斥锁持有者的堆栈跟踪
go tool pprof http://127.0.0.1:8080/debug/pprof/mutex#当前程序的执行轨迹。
go tool pprof http://127.0.0.1:8080/debug/pprof/trace
当然本地开发的话这些都是有http窗口的,但貌似对linux上开发帮助不大。感兴趣大家可以右拐google一下,有很多帖子都是。
修改gc参数,自动调优
gc值暴露了一个接口,让我们修改gc的值,那就是:debug.SetGCPercent()
,需要import runtime/debug。
ps:gc真好哇!知道我乱七八槽的不会用,只给了我一个接口。
比如:
package main
import ("runtime/debug"
)func main() {debug.SetGCPercent(30) //......
}
还是上面的代码,将gc改成30后,我查看了前六次gc的日志和gc为默认值100情况下:
# gc为30
# GODEBUG=gctrace=1 go run pprof.go
gc 1 @0.505s 0%: 0.053+2.3+1.1 ms clock, 0.64+0/0.94/1.2+14 ms cpu, 3->4->2 MB, 4 MB goal, 12 P
gc 2 @0.509s 0%: 0.034+3.6+0.002 ms clock, 0.41+0/1.3/2.7+0.033 ms cpu, 4->4->2 MB, 5 MB goal, 12 P
gc 3 @0.513s 0%: 0.031+5.0+0.002 ms clock, 0.37+0.95/0.63/3.9+0.028 ms cpu, 3->3->2 MB, 4 MB goal, 12 P
gc 4 @0.519s 0%: 0.057+3.2+0.002 ms clock, 0.68+0/4.1/0.72+0.027 ms cpu, 4->4->3 MB, 5 MB goal, 12 P
gc 5 @1.024s 0%: 0.060+6.0+0.003 ms clock, 0.72+0/3.3/4.6+0.041 ms cpu, 5->5->4 MB, 6 MB goal, 12 P
gc 6 @1.031s 0%: 0.029+11+0.074 ms clock, 0.35+0.87/6.6/0.42+0.88 ms cpu, 7->10->10 MB, 8 MB goal, 12 P# gc为100
# GODEBUG=gctrace=1 go run pprof.go
gc 1 @0.505s 0%: 0.062+2.4+0.002 ms clock, 0.74+0/1.1/1.6+0.033 ms cpu, 4->4->1 MB, 5 MB goal, 12 P
gc 2 @0.510s 0%: 0.027+6.0+0.002 ms clock, 0.33+0.18/3.9/0.55+0.032 ms cpu, 5->6->4 MB, 6 MB goal, 12 P
gc 3 @1.018s 0%: 0.12+11+0.002 ms clock, 1.5+0/11/0.29+0.030 ms cpu, 9->9->7 MB, 10 MB goal, 12 P
gc 4 @1.534s 0%: 0.044+12+0.002 ms clock, 0.53+0/13/2.4+0.030 ms cpu, 15->15->8 MB, 16 MB goal, 12 P
gc 5 @2.050s 0%: 0.046+16+0.002 ms clock, 0.55+0/3.6/13+0.032 ms cpu, 20->20->7 MB, 21 MB goal, 12 P
gc 6 @2.567s 0%: 0.075+16+0.002 ms clock, 0.90+0/6.2/15+0.034 ms cpu, 15->15->15 MB, 16 MB goal, 12 P
如何查看分析日志呢,见下一小节。
其实可以明显的看出来,gc为30时,目标堆大小,明显要比gc为100的时候要小得多。这样我们就省下来很多的内存,可以存一些自己想要的学习资料(好好好,拿内存当存储是吧…)
查看gc日志
查看gc日志信息(参考自:GODEBUG-GC):
# GODEBUG=gctrace=1 go run debug.go
gc 1 @0.049s 0%: 0.016+0.26+0.015 ms clock, 0.19+0.13/0.33/0.18+0.19 ms cpu, 4->4->0 MB, 5 MB goal, 12 P
gc 2 @0.816s 0%: 0.11+0.39+0.003 ms clock, 1.3+0.19/0.65/0.62+0.037 ms cpu, 4->4->0 MB, 5 MB goal, 12 P
gc 3 @0.824s 0%: 0.15+0.33+0.002 ms clock, 1.8+0/0.39/0.51+0.024 ms cpu, 4->4->0 MB, 5 MB goal, 12 P
含义如下:
- gc#:GC 执行次数的编号,每次叠加。
- @#s:自程序启动后到当前的具体秒数。
- #%:自程序启动以来在 GC 中花费的时间百分比。
- #+…+#:GC 的标记工作共使用的 CPU 时间占总 CPU 时间的百分比。
- #->#-># MB:分别表示 GC 启动时, GC 结束时, GC 活动时的堆大小.
- #MB goal:下一次触发 GC 的内存占用阈值。
- #P:当前使用的处理器 P 的数量
debug的其他api
有点跑题了,不过确实很有用,关于gc参数调整,goland只提供了一个接口,但是对于debug中还有其他的一些api也很有用比如说
// 强制gc 将尽可能多的内存返回给操作系统
func FreeOSMemory()
// 设置最大堆大小
func SetMaxStack(bytes int) int
// 设置最大线程数
func SetMaxThreads(threads int) int
和SetGCPercent的使用方法一样,更多api详见:https://pkg.go.dev/runtime/debug#FreeOSMemory
参考
A Guide to the Go Garbage Collector
gc问题集
debug.api
GODEBUG-GC
go pprof
gc机制和调优
ChatGPT[doge]
相关文章:

GoLand GC(垃圾回收机制)简介及调优
GC(Garbage Collector)垃圾回收机制及调优 简单理解GC机制 其实gc机制特别容易理解,就是物理内存的自动清理工。我们可以把内存想象成一个房间,程序运行时会在这个房间里存放各种东西,但有时候我们会忘记把不再需要的东西拿出去,…...

AI:40-基于深度学习的森林火灾识别
🚀 本文选自专栏:AI领域专栏 从基础到实践,深入了解算法、案例和最新趋势。无论你是初学者还是经验丰富的数据科学家,通过案例和项目实践,掌握核心概念和实用技能。每篇案例都包含代码实例,详细讲解供大家学习。 📌📌📌本专栏包含以下学习方向: 机器学习、深度学…...

37基于MATLAB平台的图像去噪,锐化,边缘检测,程序已调试通过,可直接运行。
基于MATLAB平台的图像去噪,锐化,边缘检测,程序已调试通过,可直接运行。 37matlab边缘检测图像处理 (xiaohongshu.com)...

通过Metasploit+Ngrok穿透内网长期维持访问外网Android设备
前言: 因为之前作为小白我不会在Kali Linux里面把IP映射出外网,卡在那个地方很久,后来解决了这个问题就写方法出来和大家分享分享。 环境: Kali Linux系统(https://www.kali.org/downloads/) Metasploit Ngrok Linux64位的端口转发工具(htt…...

STM32 CubeMX配置USB HID功能,及安装路径
STM32CubeMX学习笔记(46)——USB接口使用(HID自定义设备) STM32CubeMX实现STM32 USBHID双向64字节通信(下位机部分) STM32 USB HID设置(STM32CubeMX) 关于keil 5安装出现Fail to set path to Software Packs.问题解决方法...

【错误解决方案】ModuleNotFoundError: No module named ‘transformers‘
1. 错误提示 在python程序中,尝试导入一个名为transformers的模块,但Python提示找不到这个模块。 错误提示:ModuleNotFoundError: No module named ‘transformers‘ 2. 解决方案 所遇到的问题是Python无法找到名为transformers的模块&am…...

Mac 配置环境变量
Mac 配置环境变量 修改配置文件 vim ~/.bash_profile i进入编辑模式. Esc:wq 保存文件 esc:q 退出 如:jdk环境变量配置 JAVA_HOME/Library/Java/JavaVirtualMachines/jdk1.8.0_361.jdk/Contents/Home CLASSPATH J A V A H O M E / l i b / t o o l…...

如何在linux服务器上安装Anaconda与pytorch,以及pytorch卸载
如何在linux服务器上安装Anaconda与pytorch,以及pytorch卸载 1,安装anaconda1.1 下载anaconda安装包1.2 安装anaconda1.3 设计环境变量1.4 安装完成验证 2 Anaconda安装pytorch2.1 创建虚拟环境2.2 查看现存环境2.3 激活环境2.4 选择合适的pytorch版本下…...

ansble
ansble概述 Ansible是一款自动化运维工具,基于Python开发,具有批量系统配置,批量程序部署, 批量运行命令等功能。 Ansible的很多模块在执行时都会先判断目标节点是否要执行任务,所以,可以放心大胆地让Ansible去执行任务…...

git常见命令(持续更新)
判断是否为git项目 一个repo可以由多个git项目组成,一般每个git项目的根目录下都会有**.git**的文件夹;使用任何git命令前都需要打开到git项目文件下面。 git log 不带参数 // 查看本次commit修改的地方 git log-p // 可以查看FileName从建立到现在…...

Python基础入门例程23-NP23 删除好友(列表)
最近的博文: Python基础入门例程22-NP22 删除简历(列表)-CSDN博客 Python基础入门例程21-NP21 增加派对名单(二)(列表)-CSDN博客 Python基础入门例程20-NP20 增加派对名单(一&#x…...

识别鼠标选中actor_vtkInteractorStyleTrackballActor
开发环境: Windows 11 家庭中文版Microsoft Visual Studio Community 2019VTK-9.3.0.rc0vtk-example参考代码目的:学习与总结 demo解决问题:通过自定义vtkInteractorStyle类中成员函数OnLeftButtonDown,判断鼠标当前选中的是哪个…...

C++ Qt关于启动可执行文件存在的问题
如果软件具有管理员权限。请略过 使用QProcess 如果不具有管理员权限 启动可执行文件,在Debug和Release中没有问题,但是如果可执行文件启动需要管理员权限,调用函数startDetached,win10/11去要在点击用户账户控制弹窗 当使用I…...

微信定时发圈,快人一步不落索
现在的社交媒体运营已经成为了私域流量获取的重要手段,而微信作为最大的社交平台之一,更是吸引了众多使用者。但是,你是否曾经感叹过每天手动发朋友圈的繁琐?是否希望能够事先设置好定时发送的功能,让你的朋友圈自动更…...

数据分析在程序员职业中的重要性及实践应用
一、引言 在当今信息化社会的快速发展中,数据分析已经成为一项重要的职业技能。不论是从事哪个行业,都需要具备一定的数据分析能力。对于程序员而言,掌握数据分析技能不仅能够提升自身在职场中的竞争力,更能够在职业生涯中获得更…...

计算机网络_04_传输层
文章目录 1.什么是传输层2.传输层提供了什么服务3.传输层协议TCP 1.什么是传输层 传输层是OSI七层体系架构中的第四层, TCP/IP四层体系架构中的第二层, 从通信和信息处理两方面来看,“传输层”既是面向通信部分的最高层,与下面的三层一起共同构建进行网…...

3 ALS算法的优化
3.1引入时间遗忘曲线 3.2引入物品特征 3.3时间特征和物品特征加权融合 ALS优化算法的执行步骤 将式(12)对原始评分矩阵进行优化,再代入 式(3)得到了优化后的ALS算法。该算法步骤如下: 第一步:读取数据集,初始化用户-物品评分...

lvsDR模式
LVS-DR模式 是最常用的LVS负载方式 直接路由模式 Lvs调度器 只负责请求和转发 转发到真实服务器 但是响应结果 由后端服务器直接转发给客户端 不需要经过调度器处理 可以减轻Lvs调度器的负担 提高系统性能和稳定性 工作原理: 客户端发送请求到vipLVS调度器接受请求…...

Linux系统下配置王爽汇编语言环境
【步骤一】 先打开命令行,进入root模式,输入如下语句: sudo apt-get install dosbox 该语句的作用主要是安装dosbox 【步骤二】 安装完成之后,命令行输入dosbox 会进入dosbox页面: 【步骤三】 在你的主机中&…...

scss下解决父组件中使用::v-deep修改样式穿透到子组件的问题
开发中经常会用到深度选择器来修改第三方组件库等子组件的样式,这时候就用到样式穿透(style Penetration) 样式穿透的方式有:>>>、 /deep/、::v-deep这三种 使用中发现了一个问题,就是当在父组件使用了v-deep修改自身组件或者第三方…...

Redis的瓶颈在哪里?
Redis是一个开源的非常快速且高效的内存键值存储数据库,常用作缓存、消息队列、会话存储等。 Redis之所以被认为是一个快速的数据库,主要是由于以下几个方面的设计和实现: 基于内存存储: Redis是一个基于内存存储的数据库&#x…...

如何在spark中使用scikit-learn和tensorflow等第三方python包
目录 1 打包需要的python包2 修改spark配置文件 1 打包需要的python包 首先我们用conda包管理工具对我们需要的python包进行虚拟环境创建: conda create -n python37 --copy -y -q python3.7 --prefix /your/workspace/path scikit-learn tensorflow下面是对每个参…...

JS中call()、apply()、bind()改变this指向的原理
大家如果想了解改变this指向的方法,大家可以阅读本人的这篇改变this指向的六种方法 大家有没有想过这三种方法是如何改变this指向的?我们可以自己写吗? 答案是:可以自己写的 让我为大家介绍一下吧! 1.call()方法的原理…...

BUUCTF 镜子里面的世界 1
BUUCTF:https://buuoj.cn/challenges 题目描述: 下载附件,解压得到一张.png图片。 密文: 解题思路: 1、材料只有一张图片,题目提示“镜子里面的世界”结合图片中的英文“look very closely”(翻译为“仔…...

【MySQL--->内置函数】
文章目录 [TOC](文章目录) 一、日期函数二、字符串函数三、数学函数四、其他函数 一、日期函数 current_date();当前日期 current_time();当前时间 current_timestamp();当前时间戳 now();当前时间 date(‘date’);日期 date_sub(date,interval number second/minute/hour/d…...

FFmpeg 从视频流中抽取图片
抽取单个图片 使用 FFmpeg 进行截图:在终端或命令提示符下,使用以下命令进行截图: ffmpeg -i input.mp4 -ss 00:00:05 -vframes 1 output.jpg其中, -i input.mp4:指定输入的 H.264 文件路径和名称。 -ss 00:00:05&a…...

Oracle RU 19.21及 datapatch -sanity_checks
参考文档: Oracle Database Patch 35643107 - Database Release Update 19.21.0.0.231017 Datapatch User Guide (Doc ID 2680521.1) datapatch fails with ORA-04061/ORA-4065/ORA-04045/ORA-04067 due to Golden Gate triggers. (Doc ID 2301658.1) 在19.21的…...

云原生周刊:ingress2gateway 发布 | 2023.10.30
开源项目推荐 m9sweeper m9sweeper 是一个免费且简单的 Kubernetes 安全平台。它将行业标准的开源实用程序集成到一站式 Kubernetes 安全工具中,该工具可以帮助大多数 Kubernetes 管理员保护 Kubernetes 集群以及集群上运行的应用程序。 Kairos Kairos 是在 Kub…...

YOLOv8如何关闭AMP混合精度训练?
如果你是使用命令行运行的话,只需要在训练参数中添加–unamp即可.如果你是直接代码运行的话,找到这个参数parser.add_argument(‘–unamp’, action‘store_true’, help‘Unuse Automatic Mixed Precision (AMP) training’),修改为parser.add_argument(‘–unamp’, action‘…...

k8s、kubeadm安装
master(2C/4G,cpu核心数要求大于2) 192.168.86.11 docker、kubeadm、kubelet、kubectl、flannel node01(2C/2G) 192.168.86.22 docker、kubeadm、kubelet、kubectl、flannel node02(2C/2G) 1…...