Go 要违背初心吗?新提案:手动管理内存
The following article is from 脑子进煎鱼了 Author 陈煎鱼
点击关注公众号,一周多次包邮送书
来源:经授权转自 脑子进煎鱼了(ID:eddycjy)
作者:陈煎鱼
前段 SZ 疫情严重的很,公司所在的大厦都被封了 2~3 次...在家中搬砖的我,听说 Go 要变成 C++ 了?大为震惊。
今天就由煎鱼带大家看看背后的那个提案。
(结果我发这文时,这周直接变成居家办公 7 天了,车也不能随便开出去了...)
背景
由于手动管理内存普遍会给程序员带来一定的心智负担,提高一门编程语言的入门门槛(还记得大学写 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” 标准库定位一致,都是不安全的因素。
大家怎么看?以后是不是可以玩出新的花样了...
·················END·················推荐阅读
• 我去,你竟然还不会用API网关!• java双重检查锁单例真的线程安全吗?• openFeign 异步 调用丢失上下文怎么破?• 面试官:Java 设计原则中,为什么反复强调组合要优先于继承?• 为什么阿里巴巴要求 POJO 中不能使用基本数据类型?• 燃!Python实现导弹自动追踪!• 淦,为什么 "𠮷𠮷𠮷" .length !== 3
👇更多内容请点击👇