定時器中的內存泄漏


周期定時器

func main() {
    timer := time.NewTicker(1 * time.Second)  //NewTicker是周期定時器,NewTimer是普通定時器只能用一次
    for {
        <-timer.C
        fmt.Println("good")
    }
}

定時器

    time.Sleep(time.Second)
    //2Timer.C
    myTimer := time.NewTimer(time.Second * 2) //創建定時器,指定定時時長
    nowTime := <-myTimer.C                    //定時滿,系統自動寫入時間
    fmt.Println("現在時間", nowTime)
    //3 time.After
    nowTime = <-time.After(time.Second * 2)
    fmt.Println("現下時間", nowTime)

    //定時器的停止和重置
    myTimer2 := time.NewTimer(time.Second * 3)
    go func() {
        <-myTimer2.C
        fmt.Println("子go程,定時完畢")
    }()
    myTimer2.Stop() //停止
    myTimer.Reset(1 * time.Second) //重置

下面的寫法會造成內存泄漏

package main

import (
    "time"
)

func main() {
    ch := make(chan int, 10)

    go func() {
        var i= 1
        for {
            i++
            ch <- i
        }
    }()

    for {
        select {
        case x := <-ch:
            println(x)
        case <-time.After(3 * time.Minute):
            println(time.Now().Unix())
        }
    }
}
`在for循環每次select的時候,都會實例化一個一個新的定時器。該定時器在3分鍾后,才會被激活,但是激活后已經跟select無引用關系,被gc給清理掉。
換句話說,被遺棄的time.After定時任務還是在時間堆里面,定時任務未到期之前,是不會被gc清理的。
也就是說每次循環實例化的新定時器對象需要3分鍾才會可能被GC清理掉,如果我們把上面復現代碼中的3分鍾改小點,改成10秒鍾,通過top命令會發現大概10秒鍾后,該程序占用的內存增長到1.05G后基本上就不增長了`
下面的代碼是解決方案
package main

import (
    "time"
    )

func main()  {
    ch := make(chan int, 10)

    go func() {
        for {
            ch <- 100
        }
    }()

    idleDuration := 3 * time.Minute
    idleDelay := time.NewTimer(idleDuration) //綜上,在go代碼中,在for循環里不要使用select + time.After的組合,可以使用time.NewTimer替代
    defer idleDelay.Stop() //記得要關閉定時器

    for {
        idleDelay.Reset(idleDuration)

        select {
            case x := <- ch:
                println(x)
            case <-idleDelay.C:
                return
            }
    }
}





免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM