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