Go arena 民间库来了,可以手动管理内存

大家好,我是煎鱼。

上年我们有讨论过关于 Go arena 手动管理内存的相关提案。一开始还高歌猛进,但没想到后面由于严重的 API 问题(想把 arena 应用到其他的标准库中,但会引入大问题):

Go 核心团队中途咕咕咕到现在,没有新的推动和突破性进展,实属尴尬。

最近有社区的大佬有了新的动作,来自 Grafana 的 @Miguel Ángel Ortuño 开源了一个新的第三方库 ortuman/nuke,用于完成 arena 手动管理内存的诉求。

今天我们基于官方资料此进行使用分享和介绍,也好未雨绸缪一下。

温习前置知识

Arena 指的是一种从一个连续的内存区域分配一组内存对象的方式。当然了,它的重点是要手动管理内存,实现一些编程上的内存管理目标。

优点比一般的内存分配更有效率,也可以一次性释放。缺点上需要程序员在编程时手动管理,有可能会泄漏和错释放,增大了心智负担。

简单来讲就是,Arena 可以手动管理内存,可以做很多事,有利有弊。也 "容易" 崩。

快速介绍

安装

安装命令如下:

go 复制代码
go get -u github.com/ortuman/nuke

需要注意这个库要求 go >= 1.21.7,在实际下载前建议先进行升级。

使用案例

常规使用

基本使用该 arean 库的用法,代码如下:

go 复制代码
import (
	"github.com/ortuman/nuke"
)

type Foo struct{ A int }

func main() {
	arena := nuke.NewMonotonicArena(256*1024, 80)

	fooRef := nuke.New[Foo](arena "Foo")
	fooSlice := nuke.MakeSlice[Foo](arena, 0, 10 "Foo")

	for i := 0; i < 20; i++ {
		fooSlice = nuke.SliceAppend(arena, fooSlice, Foo{A: i})
	}
	// 做一些煎鱼的业务逻辑...
    
	arena.Reset(true)
	...
}
  • 初始化一个新的单一 arean 内存区域,缓冲区大小为 256KB,最大内存上限为 20MB。
  • 声明和分配一个 Foo 类型的新对象和容量为 10 个元素的 Foo 切片。
  • 业务逻辑完成后,重置所申请的 arean 内存区域(释放)。

以上是最常用的方式,相当于在某一块代码片段中进行初始化和处理。

基于 context 场景

如果我们需要在 HTTP 请求这类整个生命周期中去使用。

可以借助 context,使用如下方式:

go 复制代码
func httpHandler(w http.ResponseWriter, r *http.Request) {
    arena := nuke.NewMonotonicArena(64*1024, 10)
    defer arena.Reset(true)

    ctx := nuke.InjectContextArena(r.Context(), arena)
    processRequest(ctx)
    // 给煎鱼静悄悄干点什么...
}

func processRequest(ctx context.Context) {
    arena := nuke.ExtractContextArena(ctx)

    // ...
}

func main() {
    http.HandleFunc("/", httpHandler)    fmt.Println("Server is listening on port 8080...")
    http.ListenAndServe(":8080", nil)
}

在请求端 http context 中注入 arena,再在实际处理的地方通过 context 获取 arena,以此达到穿越整体生命周期的方式。

基于并发场景

默认场景下,nuke.NewMonotonicArena 初始化出来的 arena,有一个隐性的坑,他不是并发安全的!

大胆猜测,这是基于性能的考虑,所以没有做到一起。毕竟锁会很吃资源。而在 Go 里要去做手动内存管理的场景,多少又对性能有一定的诉求。

在有并发诉求的场景下,可以使用 NewConcurrentArena 函数:

go 复制代码
import (
	"github.com/ortuman/nuke"
)

func main() {
	arena := nuke.NewConcurrentArena(
            nuke.NewMonotonicArena(256*1024, 20),
        )
	defer arena.Reset(true)
	// 和煎鱼煎个鱼看看...
}

除了换了个初始化方法,其他用法与常规用法差不多。

也看了下官方的 Benchmarks,确实是基于性能考虑的区分并发与非并发的业务场景。QPS 越大,性能差距越大:

bash 复制代码
BenchmarkMonotonicArenaNewObject/100-8         	          124495	     15469 ns/op	       0 B/op	       0 allocs/op
BenchmarkMonotonicArenaNewObject/1000-8        	           76744	     19602 ns/op	       0 B/op	       0 allocs/op
BenchmarkMonotonicArenaNewObject/10000-8       	           24104	     50845 ns/op	       0 B/op	       0 allocs/op
BenchmarkMonotonicArenaNewObject/100000-8      	            3282	    366044 ns/op	       0 B/op	       0 allocs/op
BenchmarkConcurrentMonotonicArenaNewObject/100-8           90392	     16679 ns/op	       0 B/op	       0 allocs/op
BenchmarkConcurrentMonotonicArenaNewObject/1000-8          43753	     29823 ns/op	       0 B/op	       0 allocs/op
BenchmarkConcurrentMonotonicArenaNewObject/10000-8          8037	    149923 ns/op	       0 B/op	       0 allocs/op
BenchmarkConcurrentMonotonicArenaNewObject/100000-8          879	   1364377 ns/op

总结

今天给大家分享了 Go 官方 arena 的最新进展和情况,主体上还是由于严重 API 原因(担忧像 context 一样造成传染性)没有突破性进展。虽然有人提出可以放到 unsafe 库中,也获得了许多人表情点赞。但仍然没能打动 Go 核心团队的同学。

基于此,我们介绍了民间大佬的 arena 开源库 ortuman/nuke。基本功能和使用都能够满足需求。后续有此类业务需求时,可以随时拿起来就用!

文章持续更新,可以微信搜【脑子进煎鱼了】阅读,本文 GitHub github.com/eddycjy/blo... 已收录,学习 Go 语言可以看 Go 学习地图和路线,欢迎 Star 催更。

推荐阅读

相关推荐
童先生6 小时前
Go 项目中实现类似 Java Shiro 的权限控制中间件?
开发语言·go
幼儿园老大*7 小时前
走进 Go 语言基础语法
开发语言·后端·学习·golang·go
架构师那点事儿12 小时前
golang 用unsafe 无所畏惧,但使用不得到会panic
架构·go·掘金技术征文
于顾而言1 天前
【笔记】Go Coding In Go Way
后端·go
qq_172805591 天前
GIN 反向代理功能
后端·golang·go
follycat1 天前
2024强网杯Proxy
网络·学习·网络安全·go
OT.Ter2 天前
【力扣打卡系列】单调栈
算法·leetcode·职场和发展·go·单调栈
探索云原生2 天前
GPU 环境搭建指南:如何在裸机、Docker、K8s 等环境中使用 GPU
ai·云原生·kubernetes·go·gpu
OT.Ter2 天前
【力扣打卡系列】移动零(双指针)
算法·leetcode·职场和发展·go
码财小子2 天前
k8s 集群中 Golang pprof 工具的使用
后端·kubernetes·go