Go 基于区域的内存管理,再战手动管理!

开发 前端
在计算机科学中,基于区域的内存管理(Region-Based Memory Management)是一种内存管理方式,其中每个被分配的对象都会被归属到一个特定的区域(下也称:region)。

大家好,我是煎鱼。

最近 Go 核心团队成员 @Michael Knyszek 发起针对 memory regions 的社区讨论。

图片图片

试图引入新的基于区域的内存管理(Region-based memory management),并再次之前提到的 Arena 实验给捞一下。

“基于区域的内存管理” 是什么

在计算机科学中,基于区域的内存管理(Region-Based Memory Management)是一种内存管理方式,其中每个被分配的对象都会被归属到一个特定的区域(下也称:region)。

区域也被称为区段、场地、空间或内存上下文。一个区域是多个已分配对象的集合,这些对象可以通过一次性高效的操作被整体重新分配或释放

在优势上,区域分配在内存的分配和释放上具有较低的开销!

业务背景

煎鱼注:为什么这次叫 “业务背景”。因为我感受到了他们 Google 想强烈把这个轮子放进 Go 里的冲动。所以就不是单纯的 “背景” 了。

之前有过 Arena 实验库。该类型允许直接将数据结构分配到其中,并允许批量提前释放 Arena 内存,首次提供了手动管理内存的方式。一度在圈内闹的很大。

但,作者很无语的表示:“很不幸的是,由于 Arean 与语言和标准库的兼容性较差,将 Arean 添加到标准库的提议被无限期搁置!”

图片图片

这次再出现,想必就是 Google 团队里的 Go 同学还是想再试试。

新提案

提案背景

在原有的 Arean 提案设计中,应用的 API 要使用 arean,必须接受一个额外的参数:要分配到哪个 arean。和 context 类似。

有太多的应用程序 API 需要更新才能很好地与 Go 语言的编写方式集成,而且这会让这些应用程序接口变得更糟糕。这也是最终被很多人反对的原因之一。

因此本次新提案提出了一种可组合的方法,即以用户定义的 goroutine-local 内存区域的形式来替代原先 arena 的方式。

具体设计

本次新提案提出的是新的库,造一个新轮子去覆盖老的轮子(:doge

region 库的函数签名如下:

package region

func Do(f func())

func Ignore(g func())

一共包含两个方法。看起来很少,但有一定的 “学问” 在。

以下具体讲讲两个方法的作用和使用方向。

1、Do 方法

函数作用:该方法创建一个新的 region,并在该 region 中调用参数 f(闭包函数)。当 Do 返回时,该 region 会被销毁。

核心特性如下:

  • 隐式内存绑定:在 f 及其调用链中分配的内存可能会被隐式绑定到当前的 region。
  • 自动解绑:内存在特定场景会自动从 region 中解绑,例如:

该内存被其他 region 引用。

被其他 goroutine 或调用方(包括 Do 的调用者及其上层调用者)引用;或被其他未绑定到此 region 的内存引用。

  • 资源回收:如果 region 被销毁时仍有内存绑定到它,这些内存将由 runtime 主动回收。
  • 性能优化
  • 正确使用时,可通过内存复用降低资源成本,减轻垃圾回收(GC)的压力。
  • 错误使用可能增加资源成本,因为从 region 中解绑内存也有代价。
  • 局部性
  • region 仅对创建它的 goroutine 有效,不能传播到新创建的 goroutine。
  • 异常处理
  • 当 f 的执行因为 panic 或调用 runtime.Goexit 终止时,region 会像正常返回一样销毁。

2、Ignore 方法

函数作用:该方法让 g 及其调用链忽略当前 goroutine 上已激活使用的 region。用于排除已知生命周期长于 region 的内存,从而更高效地利用 region。

性能上,使用 Ignore 主动排除内存比自动解绑更高效。作为兜底逻辑,在没有激活 region 的情况下调用 Ignore 方法不会有任何效果。

使用例子

官方给出的最简单的基本例子。

代码如下:

var keep *int
region.Do(func() {
 w := new(int)
 x := new(MyStruct)
 y := make([]int, 10)
 z := make(map[string]string)
 *w = use(x, y, z)
 keep = w // w 从 region 中解除绑定
}) // x、y 和 z 的内存会被紧急清理,而 w 则不会。

这个例子想表述的是:所有主要的内置函数都适用于 region 功能。而且从 region 中泄漏的指针会导致其指向的内存从 region 中解除绑定。

嵌套的使用例子。代码如下:

region.Do(func() {
 z := new(MyStruct)
 var y *MyStruct
 region.Do(func() {
  x := new(MyStruct)
  use(x, z) // z 可在该内部 region 内自由使用
  y = x // x 不受任何 region 的约束
 })
 use(y)
})

这个例子主要演示 region 嵌套 region 的使用。

总结

这次 Go 核心团队想要引入支持手动做内存管理的决心感觉非常大。毕竟 arean 被 ban 了后又沉淀了一段时间,马上又推出了 region 的新提案。

Region 本次在讨论阶段,相信很快就会进入下个阶段。我们通过本文先进行快速了解。可以继续保持关注和期待!

责任编辑:武晓燕 来源: 脑子进煎鱼了
相关推荐

2024-03-12 09:10:21

GoarenaAPI

2022-11-15 09:16:59

2023-02-26 22:47:45

Go管理内存

2022-07-20 10:33:50

RustGo内存管理

2021-07-18 07:50:26

Facebook黑客恶意软件

2023-10-18 13:31:00

Linux内存

2017-02-09 21:24:22

iOS内存管理

2015-03-13 09:30:23

iOS内存管理

2023-09-11 08:47:20

Go模式uilder

2018-07-23 09:26:08

iOS内存优化

2013-10-11 17:32:18

Linux运维内存管理

2009-11-05 13:42:44

BSM

2009-07-28 09:54:23

.NET内存管理

2011-04-11 09:47:50

C++内存管理

2021-05-27 05:28:18

Linux 内存管理

2021-03-02 08:34:35

分布式管理设计

2014-07-28 15:01:56

Android内存

2014-07-21 14:40:43

Android内存

2011-06-28 15:37:34

Qt 内存

2011-08-25 22:16:31

惠普PC业务暗战
点赞
收藏

51CTO技术栈公众号