去1.20内存竞技场
#news #go #discuss #性能

使用内存竞技场增强golang内存管理

与其他编译的语言相比,GO的开创性功能之一是通过垃圾收集对未使用对象的自动内存管理。但是,这可能会通过将控制权交给内存管理过程,从而导致性能退化。在Go 1.20之前,没有提供替代机制。随着GO 1.20的引入,已经添加了一种称为内存竞技场的实验内存管理解决方案。本文探讨了在GO 1.20中使用内存竞技场的关键方面,以结合安全的动态内存分配并降低集成内存管理对应用程序性能的影响。

启用内存竞技场支持

为了支持新的内存管理机制,添加以下环境变量:

export GOEXPERIMENT=arenas

现在,要分配内存,请使用新的Arena模块:

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)
  }
}

如所示,对象地址是从单个存储区域顺序分配的,并且在调用Free()后释放了整个分配的竞技场。通过适当的用法,这种改善了代码性能,因为垃圾收集不会被要求用于竞技场。

复制数据并创建切片

如果您需要将数据复制到常规堆,请使用Clone方法,该方法将创建从竞技场到常规动态内存的结构的副本(例如,当您需要将处理结果返回到主应用程序时)。您还可以使用arena.MakeSlice(mem, initial, capacity)指定初始尺寸和潜在容量。

用反射分配内存

要根据reflect的类型分配内存,请使用新方法reflect.ArenaNew(mem, typ),该方法将指针返回到存储在mem中的竞技场中的给定类型的对象。

错误检测和解决消毒剂

使用竞技场(例如,在释放竞技场后读取或编写一个值)时检测错误,使用go run -asan(地址消毒剂)或go run -msan(内存消毒器)等机制。例如:

package main

import "arena"

type Data struct {
  value int32
}

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

与Asan/MSAN一起运行时,它将在释放竞技场后显示错误的指针使用错误。

在舞台上存放字符串

要将字符串存储在竞技场中,从字节序列创建一个内存区域,然后将字符串内容复制到其中,如下:

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))

将竞技场用于原始数据类型

该竞技场也可以用于存储结构,原始数据类型或其序列。在这种情况下,交互与使用指针的变量没有什么不同:

package main

import "arena"

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

同样,竞技场中切片的行为与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
}

检测内存泄漏

要检测使用竞技场时的内存泄漏,请使用GO中的常规分析机制(GO Tool Pprof可视化内存分配采样,可以通过运行时/PPROF模块中的函数保存)。从内存分配的角度来看,使用竞技场的工作类似于分配单个内存块(可以增长的大小)。当竞技场被释放时,所有分配的物体都无法访问。

在应用程序强烈分配内存(例如,在存储二进制树或其他相关数据结构时),可以预期改进性能。但是,假定分配的数据结构是长寿的,并且存在直到完全释放竞技场(垃圾收集器不应用于竞技场,并且连续存储区域中的分配对象未清理)。

>

>

结论

总而言之,GO 1.20中的内存竞技场的引入提供了一种实验内存管理解决方案,该解决方案允许安全的动态内存分配,同时减少集成内存管理对应用程序性能的影响。使用内存竞技场的关键方面包括通过环境变量启用支持,使用新的Arena模块分配内存,复制数据和创建切片,用reflect分配内存,使用地址和存储器的错误检测,使用地址和存储器消毒器,存储字符串和竞技场中的原始数据类型,以及在GO.

内存竞技场在应用程序深入分配内存(例如存储二进制树或其他相关数据结构)的情况下提供了潜在的性能改进。但是,重要的是要注意,预计分配的数据结构将是长期的,并且存在直到完全释放竞技场为止,因为垃圾收集器不适用于竞技场,并且连续记忆区域中的分配对象未清理。