闽公网安备 35020302035485号
//go:build unix
// 堆代码 duidaima.com
type MemoryMappedFile struct {
data []byte
}
func NewMemoryMappedFile(filename string) (*MemoryMappedFile, error) {
f, err := os.Open(filename)
if err != nil {
returnnil, err
}
defer f.Close()
// 获取文件信息(需要文件大小)
fi, err := f.Stat()
if err != nil {
returnnil, err
}
// 提取文件描述符
conn, err := f.SyscallConn()
if err != nil {
returnnil, err
}
var data []byte
connErr := conn.Control(func(fd uintptr) {
// 创建由该文件支持的内存映射
data, err = syscall.Mmap(int(fd), 0, int(fi.Size()), syscall.PROT_READ, syscall.MAP_SHARED)
})
if connErr != nil {
returnnil, connErr
}
if err != nil {
returnnil, err
}
mf := &MemoryMappedFile{data: data}
cleanup := func(data []byte) {
syscall.Munmap(data) // 忽略错误
}
runtime.AddCleanup(mf, cleanup, data)
return mf, nil
}
内存映射文件的内容直接映射到内存中。通过这段代码,当 *MemoryMappedFile 不再被引用时,内存映射会被自动清理。3.传给 cleanup 函数的参数
3.对象复活(resurrection)问题
2.内存可以立即回收
var cache sync.Map // map[string]weak.Pointer[MemoryMappedFile]
func NewCachedMemoryMappedFile(filename string) (*MemoryMappedFile, error) {
var newFile *MemoryMappedFile
for {
// 尝试从缓存加载
value, ok := cache.Load(filename)
if !ok {
// 创建新映射文件
if newFile == nil {
var err error
newFile, err = NewMemoryMappedFile(filename)
if err != nil {
returnnil, err
}
}
// 尝试安装新映射文件
wp := weak.Make(newFile)
var loaded bool
value, loaded = cache.LoadOrStore(filename, wp)
if !loaded {
runtime.AddCleanup(newFile, func(filename string) {
cache.CompareAndDelete(filename, wp)
}, filename)
return newFile, nil
}
}
// 检查缓存条目有效性
if mf := value.(weak.Pointer[MemoryMappedFile]).Value(); mf != nil {
return mf, nil
}
// 发现待清理的空条目
cache.CompareAndDelete(filename, value)
}
}
该示例展示的关键特性:3.可实现通用缓存结构(见原文通用 Cache 结构示例)
4.测试具有挑战性
2.直接追踪映射内存区域的 API