当前位置: 首页 > 知识库问答 >
问题:

golang使用arena进行内存控制为什么会出现无效访问?

卫君博
2024-04-23

在golang中,尝试使用arena进行手动内存释放

代码:

package mainimport (    "arena"    "encoding/json"    "fmt"    "runtime"    "strconv"    "strings"    "github.com/glebarez/sqlite"    "github.com/gofiber/fiber/v2"    "gorm.io/gorm")type RoadDeviceVehicle struct {    RoadPoint string}type TT struct {    PointX    string `json:"pointX"`    PointY    string `json:"pointY"`    Timestamp string `json:"timestamp"`}type TTT struct {    PointX    float32    PointY    float32    Timestamp int64}func main() {    db, err := gorm.Open(sqlite.Open("road_device_vehicle.db"), &gorm.Config{})    if err != nil {        fmt.Println(err)        panic("failed to connect database")    }    tmem := arena.NewArena()    roadVehicles := arena.MakeSlice[RoadDeviceVehicle](tmem, 0, 1500000)    db.Table("road_device_vehicle").Select("road_point").Find(&roadVehicles)    tts := arena.MakeSlice[[]TT](tmem, len(roadVehicles), len(roadVehicles))    for idx := range roadVehicles {        tts[idx] = make([]TT, 0, 20)        s := strings.Replace(roadVehicles[idx].RoadPoint, "\\", "", -1)        json.Unmarshal([]byte(s), &tts[idx])    }    tttsmem := arena.NewArena()    ttts := arena.MakeSlice[[]TTT](tttsmem, len(tts), len(tts))    for idx := range tts {        ttts[idx] = arena.MakeSlice[TTT](tttsmem, len(tts[idx]), len(tts[idx]))        for idx2 := range tts[idx] {            t, err := strconv.ParseFloat(tts[idx][idx2].PointX, 32)            if err != nil {                fmt.Println(err)                return            }            ttts[idx][idx2].PointX = float32(t)            t, err = strconv.ParseFloat(tts[idx][idx2].PointY, 32)            if err != nil {                fmt.Println(err)                return            }            ttts[idx][idx2].PointY = float32(t)            ttts[idx][idx2].Timestamp, err = strconv.ParseInt(tts[idx][idx2].Timestamp, 10, 64)            if err != nil {                fmt.Println(err)                return            }        }    }    tmem.Free()    runtime.GC()    app := fiber.New()    app.Get("/db", func(c *fiber.Ctx) error {        fmt.Println(ttts[0][0])        return c.SendString("Hello, World!")    })    app.Listen(":3000")}

在以上代码中,RoadPoint字符串类似于如下:

[{\"pointX\":\"212.13\",\"pointY\":\"61724922.54\",\"timestamp\":\"1704970150739\"},{\"pointX\":\"228.30\",\"pointY\":\"61728661.51\",\"timestamp\":\"1704970152777\"},{\"pointX\":\"188.10\",\"pointY\":\"61732802.98\",\"timestamp\":\"1704970154739\"},{\"pointX\":\"188.04\",\"pointY\":\"61737013.77\",\"timestamp\":\"1704970156738\"},{\"pointX\":\"151.57\",\"pointY\":\"61742215.45\",\"timestamp\":\"1704970158777\"}]

使用tmem.Free()之后,读取ttts字段会报错,信息如下:

accessed data from freed user arena 0x40c0007eff70fatal error: fault[signal 0xc0000005 code=0x0 addr=0x40c0007eff70 pc=0xfdf390]

请问为什么会出现这种情况,ttts不是使用tttsmem分配的吗,为什么我free了tmem后会导致ttts无法读取

使用普通的make,则可以依靠垃圾回收正确获取结果

共有1个答案

从建明
2024-04-23

在Go语言中,arena 是一个用于管理内存分配和释放的库。当你使用 arena 分配内存时,你需要明确地管理这些内存的生命周期。在你提供的代码中,你创建了两个 arena,tmemtttsmem,并分别使用它们来分配内存。

问题在于,你在释放 tmem 后尝试访问了通过 tttsmem 分配的内存。虽然 ttts 是使用 tttsmem 分配的,但 ttts 中的元素(即 TTT 切片)是通过 tmem 分配的。当你调用 tmem.Free() 时,它释放了所有由 tmem 分配的内存,这包括 tts 中的所有 TT 切片。由于 ttts 中的元素引用了这些已经被释放的 TT 切片,因此当你尝试访问 ttts 时,会出现无效访问错误。

为了解决这个问题,你需要确保正确地管理内存的生命周期。你可以考虑以下两种方法之一:

  1. 不释放 tmem:如果你不需要释放 tmem 中的内存,你可以简单地不去调用 tmem.Free()。这样,tts 中的 TT 切片将保持有效,ttts 也可以正常访问它们。
  2. 使用不同的 arena:如果你想释放 tmem 中的内存,但又想保留 ttts 中的数据,你可以为 ttsttts 使用不同的 arena。这样,当你释放 tmem 时,ttts 中的数据不会受到影响。

请注意,使用 arena 进行内存管理需要谨慎处理内存的生命周期。确保你了解何时分配和释放内存,以及这些操作如何影响你的程序。如果可能的话,使用 Go 的内置内存管理功能(如 make 和垃圾回收)可能更简单、更安全。

 类似资料:
  • 问题内容: 我只是在一本Java书中读到这句话,说Java中的对象驻留在堆上。使用堆是因为它是快速存储数据和快速检索数据的最佳方法吗? 我只有一个关于数据结构初学者的想法。我的意思是为什么不堆叠或其他? 问题答案: 堆栈的问题是您只能删除最近添加的内容。这对于局部变量非常有效,因为它们在您进入和退出函数时会来来去去,但对于生命周期不遵循单个函数的任意数据而言,效果则不太好。内存堆使您可以随意添加和

  • 最近,在运行我们的应用程序时,我们遇到了内存溢出异常。 这是异常发生之前的堆转储 看起来老根差不多吃饱了(76%)。我假设当它最终达到100%时,OOM就会发生。然而,看起来eden只有13%。 有人能解释为什么即使年轻一代还有一些空间,OOM也会发生吗?

  • 当我运行这个程序时,为什么它调用带有字符串参数重载的方法。 如果我将我的方法重写为 它将显示空白控制台,这意味着它不是String的实例,那么它为什么以这种方式调用呢?

  • 问题内容: 当我运行以下代码时: 我得到一个异常说: 为什么会出现此异常? 编辑:tmpList是一个LinkedList,其每个节点都包含DepConfAttr类型的对象。 我正在基于内存(首先是最高内存)对tmpList进行排序,这是DepConfAttr对象的属性之一。 上面的代码反映了我要通过以下代码实现的目标 问题答案: 为什么会出现此异常? 您要遍历列表,而不是通过迭代器从列表中删除一

  • 我收到这样的类型错误:- 甚至我正在使用jdk版本:-java版本"1.7.0_55"OpenJDK运行时环境(IcedTea 2.4.7)(7u55-2.4.7-1ubuntu1)OpenJDK 64位服务器VM(构建24.51-b03,混合模式) 请有人帮助我,我应该在我的项目中使用这样的组件。

  • 我想在RxJava中实现一个下载一些文件的处理队列。我想下载的文件数量可能高达100个左右。 一切都是在Android上使用RxJava 1.1.1开发的 我做错了什么?