Note, 2023-01-17. This proposal is on hold indefinitely due to serious API concerns. The GOEXPERIMENT=arena code may be changed incompatibly or removed at any time, and we do not recommend its use in production.
funcprocessRequest(req *http.Request) { // Create an arena in the beginning of the function. mem := arena.NewArena() // Free the arena in the end. defer mem.Free()
// Allocate a bunch of objects from the arena. for i := 0; i < 10; i++ { obj := arena.New[T](mem) }
// Or a slice with length and capacity. slice := arena.MakeSlice[T](mem, 100, 200) }
// newUserArena creates a new userArena ready to be used. funcnewUserArena() *userArena { a := new(userArena) SetFinalizer(a, func(a *userArena) { //g // If arena handle is dropped without being freed, then call // free on the arena, so the arena chunks are never reclaimed // by the garbage collector. a.free() }) a.refill() return a }
func(a *userArena)refill() *mspan { // If there's an active chunk, assume it's full. s := a.active //... var x unsafe.Pointer
// Check the partially-used list. lock(&userArenaState.lock) iflen(userArenaState.reuse) > 0 { //当前存在可重用的就使用重用的 } unlock(&userArenaState.lock) if s == nil { // Allocate a new one. 否则分配一个新的mspan x, s = newUserArenaChunk() if s == nil { throw("out of memory") } } a.refs = append(a.refs, x) //记录mspan.base(),报活mspan a.active = s //记录当前使用的mspan return s }
func(a *userArena)refill() *mspan { // If there's an active chunk, assume it's full. s := a.active //上次分配了mspan if s != nil { if s.userArenaChunkFree.size() > userArenaChunkMaxAllocBytes { // It's difficult to tell when we're actually out of memory // in a chunk because the allocation that failed may still leave // some free space available. However, that amount of free space // should never exceed the maximum allocation size. throw("wasted too much memory in an arena chunk") } s.next = a.fullList //将这个mspan放到fullList的链表头部 a.fullList = s a.active = nil//active置为空 s = nil } var x unsafe.Pointer
// Check the partially-used list. lock(&userArenaState.lock) iflen(userArenaState.reuse) > 0 { // //如果有可以重用的mspan则放到s中 } unlock(&userArenaState.lock) if s == nil { // Allocate a new one. x, s = newUserArenaChunk() //否则新分配一个新的 if s == nil { throw("out of memory") } } a.refs = append(a.refs, x) a.active = s return s }
**第三步:**释放的核心是这块代码
1 2 3 4 5 6 7 8 9
s := a.fullList //获取这个mspan i := len(a.refs) - 2 for s != nil { //不为空 a.fullList = s.next //指向下一个节点 s.next = nil freeUserArenaChunk(s, a.refs[i]) //释放这个mspan s = a.fullList //指向下一个节点 i-- }