Golang中如何使用runtime.Pinner固定map
Golang中如何使用runtime.Pinner固定map
param 的内存来自 Mmap,因此直接为其成员赋值会导致问题。
func InitNullMap(param *tree.ExternParam, ctx CompilerContext) error {
m := make(map[string][]string)
param.NullMap = m
// write of unpinned Go pointer 0x1400cac1ce0 to non-Go memory 0x10ed44110
// fatal error: unpinned Go pointer stored into non-Go memory
我已经成功地使用 runtime.Pinner 处理了其他常见的数据类型,例如结构体或字符串,但我发现无法处理 map。
m := make(map[string][]string)
buf := ctx.GetBuffer()
buf.Pin(m)
param.NullMap = m
// what buf is and what buf.Pin do
func New() *Buffer {
b := new(Buffer)
b.pinner = new(runtime.Pinner)
b.pinner.Pin(b)
return b
}
func (b *Buffer) Pin(os ...any) {
for _, o := range os {
b.pinner.Pin(o)
}
}
在 go/src/runtime/pinner_test.go 中没有相关示例,我也没有找到任何有用的讨论,有人能帮忙吗?
更多关于Golang中如何使用runtime.Pinner固定map的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于Golang中如何使用runtime.Pinner固定map的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Go语言中,runtime.Pinner 主要用于固定Go指针,防止它们被垃圾回收器移动,特别是当这些指针需要传递给非Go代码(如C代码)时。然而,对于map类型,直接使用 runtime.Pinner 固定可能不会按预期工作,因为map的内部结构包含指向堆内存的指针,而这些指针可能无法通过 Pinner 完全固定。
根据你的错误信息,问题在于尝试将一个未固定的Go指针存储到非Go内存中。这通常发生在将Go对象(如map)赋值给通过 Mmap 分配的内存区域时。runtime.Pinner 可以固定Go对象本身,但map内部的指针(如桶数组)可能未被固定,导致垃圾回收器移动这些内部数据,从而引发错误。
以下是一个示例,展示如何使用 runtime.Pinner 尝试固定map,但请注意,这并不能完全保证解决你的问题,因为map的内部指针可能仍然未被固定:
package main
import (
"runtime"
"unsafe"
)
func main() {
// 创建一个map
m := make(map[string][]string)
m["key"] = []string{"value"}
// 创建Pinner并尝试固定map
pinner := runtime.Pinner{}
pinner.Pin(m)
// 获取map的指针(注意:这只是map头部的指针,内部指针可能未被固定)
ptr := unsafe.Pointer(&m)
// 在这里,你可以将ptr传递给非Go代码,但风险仍然存在
// 因为map的内部结构(如桶)可能被垃圾回收器移动
_ = ptr
// 保持pinner存活,直到非Go代码不再需要map
defer pinner.Unpin()
}
然而,对于你的具体场景,将map赋值给 param.NullMap(其中 param 的内存来自 Mmap),更可靠的方法是避免直接使用map,或者考虑使用其他数据表示形式。例如,你可以将map序列化为字节切片,然后存储到 Mmap 内存中。以下是一个示例:
func InitNullMap(param *tree.ExternParam, ctx CompilerContext) error {
m := make(map[string][]string)
// 假设你有序列化和反序列化map的函数
data, err := serializeMap(m)
if err != nil {
return err
}
// 将数据复制到Mmap内存中
// 假设param.NullMap是一个字节切片或类似的可存储数据的类型
param.NullMap = data
return nil
}
func serializeMap(m map[string][]string) ([]byte, error) {
// 实现map的序列化,例如使用JSON、gob或自定义格式
// 这里只是一个示例,你需要根据实际需求实现
return []byte{}, nil
}
如果你必须使用map,并且 param.NullMap 是map类型,那么问题可能更复杂。在这种情况下,确保整个map(包括内部指针)不被垃圾回收器移动是困难的。你可能需要重新设计,避免将Go map存储到非Go内存中。
总之,直接使用 runtime.Pinner 固定map可能无法完全解决问题。建议考虑替代方案,如序列化或重新设计数据存储方式。

