最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

golang容易導致內(nèi)存泄漏的6種情況匯總

 更新時間:2023年01月09日 09:44:01   作者:Yuan_sr  
內(nèi)存泄漏是我們在生產(chǎn)環(huán)境中必須面臨的問題,下面這篇文章主要給大家介紹了關(guān)于golang容易導致內(nèi)存泄漏的6種情況,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下

1. 定時器使用不當

1.1 time.After()的使用

默認的time.After()是會有內(nèi)存泄露問題的,因為每次time.After(duration x)會產(chǎn)生NewTimer(),在duration x到期之前,新創(chuàng)建的timer不會被GC,到期之后才會GC。

隨著時間推移,尤其是duration x很大的話,會產(chǎn)生內(nèi)存泄露的問題,應特別注意

for true {
	select {
	case <-time.After(time.Minute * 3):
    // do something
  default:
		time.Sleep(time.Duration(1) * time.Second)
	}
}

為了保險起見,使用NewTimer()或者NewTicker()代替的方式主動釋放資源,兩者的區(qū)別請自行查閱或看我往期文章https://blog.csdn.net/weixin_38299404/article/details/119352884

timer := time.NewTicker(time.Duration(2) * time.Second)
defer timer.Stop()
for true {
	select {
	case <-timer.C:
		// do something
	default:
		time.Sleep(time.Duration(1) * time.Second)
	}
}

1.2 time.NewTicker資源未及時釋放

在使用time.NewTicker時需要手動調(diào)用Stop()方法釋放資源,否則將會造成永久性的內(nèi)存泄漏

timer := time.NewTicker(time.Duration(2) * time.Second)
// defer timer.Stop()
for true {
	select {
	case <-timer.C:
		// do something
	default:
		time.Sleep(time.Duration(1) * time.Second)
	}
}

2. select阻塞

使用select時如果有case沒有覆蓋完全的情況且沒有default分支進行處理,最終會導致內(nèi)存泄漏

2.1 導致goroutine阻塞的情況

func main() {
    ch1 := make(chan int)
    ch2 := make(chan int)
    ch3 := make(chan int)
    go Getdata("https://www.baidu.com",ch1)
    go Getdata("https://www.baidu.com",ch2)
    go Getdata("https://www.baidu.com",ch3)
    select{
        case v:=<- ch1:
            fmt.Println(v)
        case v:=<- ch2:
            fmt.Println(v)
    }
}

上述這種情況會阻塞在ch3的消費處導致內(nèi)存泄漏

2.2 循環(huán)空轉(zhuǎn)導致CPU暴漲

func main() {
	fmt.Println("main start")
	msgList := make(chan int, 100)
	go func() {
		for {
			select {
			case <-msgList:
			default:
 
			}
		}
	}()
	
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)
	s := <-c
	
	fmt.Println("main exit.get signal:", s)
}

上述for循環(huán)條件一旦命中default則會出現(xiàn)循環(huán)空轉(zhuǎn)的情況,并最終導致CPU暴漲

3. channel阻塞

channel阻塞主要分為寫阻塞和讀阻塞兩種情況

空channel

func channelTest() {
  	//聲明未初始化的channel讀寫都會阻塞
    var c chan int
  	//向channel中寫數(shù)據(jù)
    go func() {
        c <- 1
        fmt.Println("g1 send succeed")
        time.Sleep(1 * time.Second)
    }()
  	//從channel中讀數(shù)據(jù)
    go func() {
        <-c
        fmt.Println("g2 receive succeed")
        time.Sleep(1 * time.Second)
    }()
    time.Sleep(10 * time.Second)
}

寫阻塞

無緩沖channel的阻塞通常是寫操作因為沒有讀而阻塞

func channelTest() {
    var c = make(chan int)
  	//10個協(xié)程向channel中寫數(shù)據(jù)
    for i := 0; i < 10; i++ {
        go func() {
            <- c
            fmt.Println("g1 receive succeed")
            time.Sleep(1 * time.Second)
        }()
    }
  	//1個協(xié)程叢channel讀數(shù)據(jù)
    go func() {
        c <- 1
        fmt.Println("g2 send succeed")
        time.Sleep(1 * time.Second)
    }()
  	//會有寫的9個協(xié)程阻塞得不到釋放
    time.Sleep(10 * time.Second)
}

有緩沖的channel因為緩沖區(qū)滿了,寫操作阻塞

func channelTest() {
    var c = make(chan int, 8)
  	//10個協(xié)程向channel中寫數(shù)據(jù)
    for i := 0; i < 10; i++ {
        go func() {
            <- c
            fmt.Println("g1 receive succeed")
            time.Sleep(1 * time.Second)
        }()
    }
  	//1個協(xié)程叢channel讀數(shù)據(jù)
    go func() {
        c <- 1
        fmt.Println("g2 send succeed")
        time.Sleep(1 * time.Second)
    }()
  	//會有寫的幾個協(xié)程阻塞寫不進去
    time.Sleep(10 * time.Second)
}

讀阻塞

期待從channel讀數(shù)據(jù),結(jié)果沒有g(shù)oroutine往進寫數(shù)據(jù)

func channelTest() {
   var c = make(chan int)
  //1個協(xié)程向channel中寫數(shù)據(jù)
  go func() {
    <- c
    fmt.Println("g1 receive succeed")
    time.Sleep(1 * time.Second)
  }()
  //10個協(xié)程叢channel讀數(shù)據(jù)
  for i := 0; i < 10; i++ {
    go func() {
        c <- 1
        fmt.Println("g2 send succeed")
        time.Sleep(1 * time.Second)
    }()
  }
  //會有讀的9個協(xié)程阻塞得不到釋放
  time.Sleep(10 * time.Second)
}

4. goroutine導致的內(nèi)存泄漏

4.1 申請過多的goroutine

例如在for循環(huán)中申請過多的goroutine來不及釋放導致內(nèi)存泄漏

4.2 goroutine阻塞

4.2.1 I/O問題

I/O連接未設置超時時間,導致goroutine一直在等待,代碼會一直阻塞。

4.2.2 互斥鎖未釋放

goroutine無法獲取到鎖資源,導致goroutine阻塞

//協(xié)程拿到鎖未釋放,其他協(xié)程獲取鎖會阻塞
func mutexTest() {
    mutex := sync.Mutex{}
    for i := 0; i < 10; i++ {
        go func() {
            mutex.Lock()
            fmt.Printf("%d goroutine get mutex", i)
      			//模擬實際開發(fā)中的操作耗時
            time.Sleep(100 * time.Millisecond)
        }()
    }
    time.Sleep(10 * time.Second)
}

4.2.3 死鎖

當程序死鎖時其他goroutine也會阻塞

func mutexTest() {
    m1, m2 := sync.Mutex{}, sync.RWMutex{}
  	//g1得到鎖1去獲取鎖2
    go func() {
        m1.Lock()
        fmt.Println("g1 get m1")
        time.Sleep(1 * time.Second)
        m2.Lock()
        fmt.Println("g1 get m2")
    }()
    //g2得到鎖2去獲取鎖1
    go func() {
        m2.Lock()
        fmt.Println("g2 get m2")
        time.Sleep(1 * time.Second)
        m1.Lock()
        fmt.Println("g2 get m1")
    }()
  	//其余協(xié)程獲取鎖都會失敗
    go func() {
        m1.Lock()
        fmt.Println("g3 get m1")
    }()
    time.Sleep(10 * time.Second)
}

4.2.4 waitgroup使用不當

waitgroup的Add、Done和wait數(shù)量不匹配會導致wait一直在等待

5. slice 引起的內(nèi)存泄漏

當兩個slice 共享地址,其中一個為全局變量,另一個也無法被GC;

append slice 后一直使用,沒有進行清理。

var a []int
 
func test(b []int) {
        a = b[:3]
        return
}

6. 數(shù)組的值傳遞

由于數(shù)組時Golang的基本數(shù)據(jù)類型,每個數(shù)組占用不通的內(nèi)存空間,生命周期互不干擾,很難出現(xiàn)內(nèi)存泄漏的情況,但是數(shù)組作為形參傳輸時,遵循的時值拷貝,如果函數(shù)被多個goroutine調(diào)用且數(shù)組過大時,則會導致內(nèi)存使用激增。

//統(tǒng)計nums中target出現(xiàn)的次數(shù)
func countTarget(nums [1000000]int, target int) int {
    num := 0
    for i := 0; i < len(nums) && nums[i] == target; i++ {
        num++
    }
    return num
}

因此對于大數(shù)組放在形參場景下通常使用切片或者指針進行傳遞,避免短時間的內(nèi)存使用激增。

總結(jié)

到此這篇關(guān)于golang容易導致內(nèi)存泄漏的6種情況的文章就介紹到這了,更多相關(guān)golang內(nèi)存泄漏內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 使用Golang開發(fā)一個簡易版shell

    使用Golang開發(fā)一個簡易版shell

    這篇文章主要為大家詳細介紹了如何使用Golang開發(fā)一個簡易版shell,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2024-02-02
  • Go語言字符串及strings和strconv包使用實例

    Go語言字符串及strings和strconv包使用實例

    字符串是工作中最常用的,值得我們專門的練習一下,下面這篇文章主要給大家介紹了關(guān)于Go語言字符串及strings和strconv包使用的相關(guān)資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-06-06
  • 解決golang時間字符串轉(zhuǎn)time.Time的坑

    解決golang時間字符串轉(zhuǎn)time.Time的坑

    這篇文章主要介紹了解決golang時間字符串轉(zhuǎn)time.Time的坑,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • Go語言常見錯誤之a(chǎn)ny沒傳遞任何信息解決分析

    Go語言常見錯誤之a(chǎn)ny沒傳遞任何信息解決分析

    Go語言,由于其高效強大的并行處理能力和優(yōu)雅簡單的設計哲學,一直以來都是編程世界的寵兒,然而,對于一些Go新手和甚至熟悉Go的程序員也可能會遇到一個常見的錯誤:?any沒傳遞任何信息,那么,如何規(guī)避這個錯誤,本文將揭示其中的秘密
    2024-01-01
  • golang 微服務之gRPC與Protobuf的使用

    golang 微服務之gRPC與Protobuf的使用

    這篇文章主要介紹了golang 微服務之gRPC與Protobuf的使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-02-02
  • go語言入門環(huán)境搭建及GoLand安裝教程詳解

    go語言入門環(huán)境搭建及GoLand安裝教程詳解

    這篇文章主要介紹了go語言入門環(huán)境搭建及GoLand安裝教程詳解,需要的朋友可以參考下
    2020-12-12
  • 重學Go語言之如何使用Redis

    重學Go語言之如何使用Redis

    Redis是我們開發(fā)應用程序中很常用的NoSQL數(shù)據(jù)庫,那么在Go語言中要如何連接和操作Redis呢,在這篇文章中,我們就來一起來探究一下吧
    2023-08-08
  • 一文教你打造一個簡易的Golang日志庫

    一文教你打造一個簡易的Golang日志庫

    這篇文章主要為大家詳細介紹了如何使用不超過130行的代碼,通過一系列g(shù)olang的特性,來打造一個簡易的golang日志庫,感興趣的小伙伴可以了解一下
    2023-06-06
  • GO語言實現(xiàn)簡單TCP服務的方法

    GO語言實現(xiàn)簡單TCP服務的方法

    這篇文章主要介紹了GO語言實現(xiàn)簡單TCP服務的方法,實例分析了Go語言實現(xiàn)TCP服務的技巧,需要的朋友可以參考下
    2015-03-03
  • Golang如何實現(xiàn)任意進制轉(zhuǎn)換的方法示例

    Golang如何實現(xiàn)任意進制轉(zhuǎn)換的方法示例

    進制轉(zhuǎn)換是人們利用符號來計數(shù)的方法,進制轉(zhuǎn)換由一組數(shù)碼符號和兩個基本因素“基數(shù)”與“位權(quán)”構(gòu)成,這篇文章主要給大家介紹了關(guān)于Golang如何實現(xiàn)10進制轉(zhuǎn)換62進制的方法,文中給出了詳細的示例代碼供大家參考學習學習,下面隨著小編來一起學習學習吧。
    2017-09-09

最新評論

永川市| 云龙县| 建昌县| 宜城市| 宜宾县| 长沙县| 秦皇岛市| 塔河县| 京山县| 雷波县| 台安县| 南陵县| 怀远县| 寿阳县| 西城区| 福清市| 当雄县| 丰宁| 诏安县| 呼玛县| 巴彦县| 桂平市| 衡阳市| 新源县| 丰镇市| 开江县| 彰武县| 明星| 同仁县| 阜新| 大邑县| 赣州市| 长乐市| 临汾市| 冷水江市| 灌云县| 雅安市| 潮州市| 涿鹿县| 闸北区| 新安县|