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

开发 前端
本提案所提到的 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” 标准库定位一致,都是不安全的因素。

大家怎么看?

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

2021-02-25 15:51:41

Go语言模糊测试功能

2022-10-24 08:55:13

Go工具链开发者

2024-03-12 09:10:21

GoarenaAPI

2023-12-27 08:03:53

Go优化代码

2021-12-13 08:52:42

Go 泛型

2023-02-26 22:47:45

Go管理内存

2021-08-09 10:36:20

GoSlices Maps

2022-07-13 08:53:28

函数Go语言

2023-10-30 08:49:23

Go提案离职

2021-12-27 07:59:50

ECMAScript JSON模块Node.js

2023-06-27 13:35:04

RedHat开源商业

2022-01-11 12:13:33

JavaScript编程语言

2023-08-14 08:00:00

Go 标准库HTTP 路由器

2021-07-27 13:08:52

微软Chrome新提案

2021-01-14 05:20:48

Go语言泛型

2022-09-05 08:55:15

Go2提案语法

2019-07-25 15:10:29

QQ手机QQ

2022-06-08 10:46:00

CSS前端

2010-08-26 10:20:43

2023-08-30 13:23:12

异步编程JavaScript
点赞
收藏

51CTO技术栈公众号