MST

星途 面试题库

面试题:Go中常见导致内存泄漏的场景及防范

请列举至少两种Go语言中可能导致内存泄漏的常见场景,并说明如何防范。
50.1万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

常见导致内存泄漏场景及防范方法

  1. 未关闭的文件描述符
    • 场景:在Go语言中,如果打开了文件、网络连接等资源,但没有及时关闭,会导致文件描述符泄漏,随着不断打开新的资源,最终耗尽系统资源。例如使用os.Open打开文件后忘记调用file.Close()
    • 防范:使用defer关键字在函数结束时关闭文件。如下示例:
func readFile() {
    file, err := os.Open("test.txt")
    if err != nil {
        log.Fatal(err)
    }
    defer file.Close()
    // 后续文件操作
}
  1. 未释放的goroutine
    • 场景:当一个goroutine持有对某些对象的引用,而这些对象无法被垃圾回收器回收,且goroutine永不结束时,就会发生内存泄漏。例如,在一个goroutine中创建了一个大的切片,但是该goroutine一直处于运行状态,没有释放切片的内存。
    • 防范:确保goroutine有合适的退出机制。可以通过通道(channel)发送信号来通知goroutine退出。示例如下:
func worker(done chan struct{}) {
    bigSlice := make([]int, 1000000)
    // 模拟工作
    time.Sleep(time.Second)
    <-done
}

func main() {
    done := make(chan struct{})
    go worker(done)
    // 主程序工作一段时间后
    time.Sleep(2 * time.Second)
    close(done)
}
  1. 缓存使用不当
    • 场景:如果在程序中使用了缓存(如map作为缓存),并且缓存中的数据不断增加但从不清理,会导致内存占用持续上升。例如,一个缓存函数结果的map,随着调用次数增加,缓存中数据无限增长。
    • 防范:为缓存设置过期策略,定期清理缓存中的过期数据。可以使用定时任务结合一个带有过期时间的结构体来实现。示例如下:
type CachedValue struct {
    value     interface{}
    expiration time.Time
}

var cache = make(map[string]CachedValue)

func setCache(key string, value interface{}, duration time.Duration) {
    cache[key] = CachedValue{
        value:     value,
        expiration: time.Now().Add(duration),
    }
}

func getCache(key string) (interface{}, bool) {
    if val, ok := cache[key]; ok {
        if time.Now().After(val.expiration) {
            delete(cache, key)
            return nil, false
        }
        return val.value, true
    }
    return nil, false
}

func cleanCache() {
    for key, val := range cache {
        if time.Now().After(val.expiration) {
            delete(cache, key)
        }
    }
}

func main() {
    go func() {
        for {
            time.Sleep(5 * time.Minute)
            cleanCache()
        }
    }()
    // 其他业务逻辑
}