1.变量遮蔽带来的非意料行为

func getA() (int, error) {
    return 3, errors.New("getAError")
}

func main() {
    var a int
    var err error
    if true {
        a, err := getA() //新的代码块会产生新的变量
        fmt.Println(a, err)
    }
    fmt.Println(a, err)
}

输出
3 getAError
0 <nil>

func main2() {
    var a int
    var err error
    a, err := getA() //同一个代码块内,必须有一个新变量才能用:=
    fmt.Println(a, err)
    fmt.Println(a, err)
}
func getA() (int, error) {
    return 3, errors.New("getAError: invalid")
}

2. delete不能删除NaN的key

delete 删除的KEY必须是可以自反的,NaN!=NaN,所以不能删除

package main

import "fmt"

func main() {
    s := []int{1, 2, 3}
    clear(s)
    fmt.Println(s) // [0 0 0]

    a := [4]int{5, 6, 7, 8}
    clear(a[1:3])
    fmt.Println(a) // [5 0 0 8]

    m := map[float64]float64{}
    x := 0.0
    m[x] = x
    x /= x // x变成了NaN
    m[x] = x
    fmt.Println(len(m)) // 2
    for k := range m {
        delete(m, k) //给的NaN的Key,但是删不掉
    }
    fmt.Println(len(m)) // 1
    clear(m)
    fmt.Println(len(m)) // 0
}

[0 0 0]
[5 0 0 8]
2
1
0

3.go map存在内存泄露

如果我们频繁插入数据然后频繁删除,最后导致map可能内存泄露,因为delete操作不会真正地删除,而是将对应位置的数据清零.但没有从内存删除.存储桶还在.
clear进行清空操作,且能删除NaN的Key,不像delete.但是clear同样不能避免map内存泄露


func main() {
    PrintMemUsage()

    m := map[int][1024 * 1024]int8{}
    for i := 0; i < 1024; i++ {
        m[i] = [1024 * 1024]int8{}
    }
    PrintMemUsage()
    for i := 0; i < 1024; i++ {
        delete(m, i)
    }
    PrintMemUsage()

    fmt.Println(len(m))
    runtime.KeepAlive(m)

    time.Sleep(1000000 * time.Millisecond)
}

func PrintMemUsage() {
    runtime.GC()
    var m runtime.MemStats
    runtime.ReadMemStats(&m)
    // For info on each, see: https://golang.org/pkg/runtime/#MemStats
    fmt.Printf("Alloc = %v MiB", bToMb(m.Alloc))
    fmt.Printf("\tTotalAlloc = %v MiB", bToMb(m.TotalAlloc))
    fmt.Printf("\tSys = %v MiB", bToMb(m.Sys))
    fmt.Printf("\tFrees = %v\n", m.Frees)

    println("------------")
}
func bToMb(b uint64) uint64 {
    return b / 1024 / 1024
}

发表回复