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 催更。

推荐阅读

相关推荐
研究司马懿20 小时前
【云原生】Gateway API高级功能
云原生·go·gateway·k8s·gateway api
梦想很大很大1 天前
使用 Go + Gin + Fx 构建工程化后端服务模板(gin-app 实践)
前端·后端·go
lekami_兰2 天前
MySQL 长事务:藏在业务里的性能 “隐形杀手”
数据库·mysql·go·长事务
却尘2 天前
一篇小白也能看懂的 Go 字符串拼接 & Builder & cap 全家桶
后端·go
ん贤2 天前
一次批量删除引发的死锁,最终我选择不加锁
数据库·安全·go·死锁
mtngt112 天前
AI DDD重构实践
go
Grassto4 天前
12 go.sum 是如何保证依赖安全的?校验机制源码解析
安全·golang·go·哈希算法·go module
Grassto6 天前
11 Go Module 缓存机制详解
开发语言·缓存·golang·go·go module
程序设计实验室7 天前
2025年的最后一天,分享我使用go语言开发的电子书转换工具网站
go
我的golang之路果然有问题7 天前
使用 Hugo + GitHub Pages + PaperMod 主题 + Obsidian 搭建开发博客
golang·go·github·博客·个人开发·个人博客·hugo