2

Go 要违背初心吗?新提案:手动管理内存

 1 year ago
source link: https://www.51cto.com/article/722697.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Go 要违背初心吗?新提案:手动管理内存

作者:陈煎鱼 2022-11-15 09:16:59
本提案所提到的 Arena,指的是一种从一个连续的内存区域分配一组内存对象的方式。优点是 arena 中的对象分配通常比一般的内存分配更有效率,所分配的对象可以一次性释放,以此达到内存管理或垃圾收集的开销最小。

由于手动管理内存普遍会给程序员带来一定的心智负担,提高一门编程语言的入门门槛(还记得大学写 OC 时经常有同学写着写崩了...)。

对应到 Go 语言上,他是一门带垃圾回收的编程语言。也就是说不需要程序员手动的去管理、释放程序的内存。

图片

无需手动管理也是 Go 核心开发团队一直引以为傲的特性之一。

最近有人发起了一个新提案《proposal: arena: new package providing memory arenas》,引起了非常广泛的讨论。

图片

接下来我们将面向该提案进行学习和了解。

本提案所提到的 Arena,指的是一种从一个连续的内存区域分配一组内存对象的方式。优点是 arena 中的对象分配通常比一般的内存分配更有效率,所分配的对象可以一次性释放,以此达到内存管理或垃圾收集的开销最小。

其建议在 Go 的标准库中支持 arena。标准 API 如下:

package arena

type Arena struct {
 // contains filtered or unexported fields
}

// New allocates a new arena.
func New() *Arena

// Free frees the arena (and all objects allocated from the arena) so that
// memory backing the arena can be reused fairly quickly without garbage
// collection overhead.  Applications must not call any method on this
// arena after it has been freed.
func (a *Arena) Free()

// New allocates an object from arena a.  If the concrete type of objPtr is
// a pointer to a pointer to type T (**T), New allocates an object of type
// T and stores a pointer to the object in *objPtr.  The object must not
// be accessed after arena a is freed.
func (a *Arena) New(objPtr interface{})

// NewSlice allocates a slice from arena a.  If the concrete type of slicePtr
// is *[]T, NewSlice creates a slice of element type T with the specified
// capacity whose backing store is from the arena a and stores it in
// *slicePtr. The length of the slice is set to the capacity.  The slice must
// not be accessed after arena a is freed.
func (a *Arena) NewSlice(slicePtr interface{}, cap int)

这一实践已经在 Google 得到了应用,且在一些大型应用程序中节省了高达 15% 的CPU和内存使用,这主要是由于减少了垃圾收集的CPU时间和堆内存使用所带来的效果。

arena 若成为标准库的使用的例子:

import (
 “arena”
 …
)

type T struct {
 val int
}

func main() {
 a := arena.New()
 var ptrT *T
 a.New(&ptrT)
 ptrT.val = 1

 var sliceT []T
 a.NewSlice(&sliceT, 100)
 sliceT[99].val = 4

 a.Free()
}

手动调用 arena.New​ 方法分配 arena 内存,再调用 Free 方法进行释放。

当然,一般提案中所提到的 arena 并不会在一门带垃圾回收的编程语言中实现。因为会操作到内存就有可能会不安全,不符合带垃圾回收的语言定义。

该库底层采取了动态检查来确保 arena 释放内存的操作是安全的。若出现异常情况,就会终止释放。

围绕这这个新的提案,评论区的网友们争议的非常多。有的会疑惑,为什么一定要放在标准库,放第三方库不行吗?

实际上在第三方库中很难安全地做到这一点,因为一个在 arena 库中分配的变量,他包含指向外部的内存指针,要确保性能下让 GC 知道他,否则可能会导致错误的释放。

图片

当然,也有人提出,这 Go 就变成像 C++ 一样,忘记 free、重复 free、提前 free,与 Go 原先标榜的简洁相差甚远。

现阶段该提案还在积极探讨的阶段,原型代码也已经提交《runtime: prototype CL showing possible implementation of arenas》有兴趣的小伙伴可以抽时间看看。

这个提案争议较大,你很难说他是一个库,还是一个语言的根本性变更。你一旦在原生标准库支持了,其他关联的也必然会支持其 API,自然而然就植入进去了,与 “unsafe” 标准库定位一致,都是不安全的因素。

大家怎么看?


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK