2017-02-13 153 views
1

我試圖理解併發和夠程,並有大約如下的實驗代碼幾個問題:爲什麼這個golang程序會造成內存泄漏?

  1. 爲什麼會創建一個內存泄漏?我認爲在goroutine結束時返回將允許與其關聯的內存得到清理。
  2. 爲什麼我的循環幾乎不會達到999?實際上,當我輸出到一個文件並研究輸出時,我注意到它很少打印兩位數的整數;第一次打印「99」是第2461行,第一次打印「999」第6120行。這種行爲對我來說是意想不到的,這顯然意味着我不瞭解goroutine調度的情況。

免責聲明:

小心運行下面的代碼,它可以造成系統崩潰,如果你不幾秒鐘後停止它!

CODE

package main 

import (
    "fmt" 
    "sync" 
) 

func main() { 
    var wg sync.WaitGroup 
    for { 
     // spawn four worker goroutines 
     spawnWorkers(4, wg) 
     // wait for the workers to finish 
     wg.Wait() 
    } 
} 

func spawnWorkers(max int, wg sync.WaitGroup) { 
    for n := 0; n < max; n++ { 
     wg.Add(1) 
     go func() { 
      defer wg.Done() 
      f(n) 
      return 
     }() 
    } 
} 

func f(n int) { 
    for i := 0; i < 1000; i++ { 
     fmt.Println(n, ":", i) 
    } 
} 
+7

你複製'同步.WaitGroup';代之以傳遞一個指針。 –

+2

運行'go vet'會顯示錯誤。 – JimB

+0

嗨@TimCooper,關於內存泄漏,你是對的!這確實確定了問題#1,但是在這種情況下,例程4運行的遠遠超過其他問題;當輸出到一個.txt文件時,我可以看到第一次#1運行是線1640001.這對我來說沒有多大意義。 – dpog

回答

2

感謝Tim庫珀,JimB和Greg提出的寶貴意見。代碼的更正版本將在下面發佈以供參考。

兩個修復均通過引用,其固定在所述內存泄漏WaitGroup通過,並且正確地傳遞Ñ到匿名的goroutine,和

package main 

import (
    "fmt" 
    "sync" 
) 

func main() { 
    var wg sync.WaitGroup 
    for { 
     // spawn four worker goroutines 
     spawnWorkers(4,&wg) 
     // wait for the workers to finish 
     wg.Wait() 
    } 
} 

func spawnWorkers(max int, wg *sync.WaitGroup) { 
    for n := 0; n < max; n++ { 
     wg.Add(1) 
     go func(n int) { 
      defer wg.Done() 
      f(n) 
      return 
     }(n) 
    } 
} 

func f(n int) { 
    for i := 0; i < 1000; i++ { 
     fmt.Println(n, ":", i) 
    } 
}