Go 1.20 memory arena
Tags: go, performance, news
Published: 2023-07-22 12:05:22

## Enhancing Golang Memory Management with Memory Arenas

One of the groundbreaking features of Go, compared to other compiled languages, is its automatic memory management of unused objects through garbage collection. However, this can lead to performance degradation by handing over control to the memory management process. Until Go 1.20, no alternative mechanism was provided. With the introduction of Go 1.20, an experimental memory management solution called Memory Arena has been added. This article explores the key aspects of using Memory Arenas in Go 1.20 to combine safe dynamic memory allocation and reduce the impact of integrated memory management on application performance.

### Enabling Memory Arena Support

To enable support for the new memory management mechanism, add the following environment variable:

```bash
export GOEXPERIMENT=arenas
```

Now, to allocate memory, use the new arena module:

```go
package main

import "arena"

type Person struct{
  Lastname string
  Firstname string
}

func main() {
  mem := arena.NewArena()
  defer mem.Free()

  for i:=0; i<10; i++ {
    obj := arena.New[Person](mem)
    print(obj)
  }
}
```

As demonstrated, object addresses are allocated sequentially from a single memory area, and the entire allocated arena is freed after calling `Free()`. With proper usage, this improves code performance since garbage collection will not be called for the arena. 

### Copying Data and Creating Slices

If you need to copy data to a regular heap, use the `Clone` method, which creates a copy of the structure from the arena to regular dynamic memory (for example, when you need to return the processing result to the main application). You can also create slices in the arena by specifying the initial size and potential capacity using `arena.MakeSlice(mem, initial, capacity)`.

### Allocating Memory with Reflect

To allocate memory based on a type from `reflect`, use the new method `reflect.ArenaNew(mem, typ)` which returns a pointer to an object of the given type allocated in the arena stored in `mem`.

### Error Detection and Address Sanitizers

Detect errors when using the arena (for example, reading or writing a value to a structure after freeing the arena) using mechanisms like `go run -asan` (Address Sanitizer) or `go run -msan` (Memory Sanitizer). For example:

```go
package main

import "arena"

type Data struct {
  value int32
}

func main() {
  mem := arena.NewArena()
  v := arena.New[Data](mem)
  mem.Free()
  v.value = 1
}
```

When running with asan/msan, it will show an error of incorrect pointer usage after freeing the arena.

### Storing Strings in the Arena

To store strings in the arena, create a memory region from a byte sequence and copy the string contents into it, like this:

```go
src := "original"

mem := arena.NewArena()
defer mem.Free()

bs := arena.MakeSlice[byte](mem, len(src), len(src))
copy(bs, src)
str := unsafe.String(&bs[0], len(bs))
```

### Using the Arena for Primitive Data Types

The arena can also be used for storing structures, primitive data types, or their sequences. In this case, the interaction is no different from working with a pointer to a variable:

```go
package main

import "arena"

func main() {
  mem := arena.NewArena()
  defer mem.Free()
  v := arena.New[int32](mem)
  *v = 10
  println(*v)
}
```

Similarly, the behavior of slices in the arena is no different from regular slices in Go:

```go
package main

import "arena"

func main() {
  mem := arena.NewArena()
  defer mem.Free()
  v := arena.MakeSlice[int32](mem,50,100)
  v[49] = 10;
  v = append(v, 20)
  println(v[49])		//10
  println(v[50])		//20
  println(len(v))		//51
  println(cap(v))		//100
}
```

### Detecting Memory Leaks

To detect memory leaks when using arenas, use the usual profiling mechanisms in Go (go tool pprof for visualizing memory allocation sampling, which can be saved via functions in the runtime/pprof module). From the point of view of memory allocation, working with an arena is similar to allocating a single memory block (which can grow in size). When the arena is freed, all objects allocated in it become inaccessible.

Performance improvements can be expected in cases where the application intensively allocates memory (for example, when storing binary trees or other related data structures). However, it is assumed that the allocated data structures are long-lived and exist until the arena is freed entirely (the garbage collector is not applied to the arena, and allocated objects in the contiguous memory area are not cleaned up).

## Conclusion

In summary, the introduction of Memory Arenas in Go 1.20 provides an experimental memory management solution that allows for safe dynamic memory allocation while reducing the impact of integrated memory management on application performance. Key aspects of using Memory Arenas include enabling support through an environment variable, allocating memory using the new arena module, copying data and creating slices, allocating memory with `reflect`, error detection using Address and Memory Sanitizers, storing strings and primitive data types in the arena, and detecting memory leaks using profiling mechanisms in Go.

Memory Arenas offer potential performance improvements in cases where applications intensively allocate memory, such as storing binary trees or other related data structures. However, it is important to note that the allocated data structures are expected to be long-lived and exist until the arena is freed entirely, as the garbage collector does not apply to the arena and allocated objects in the contiguous memory area are not cleaned up.