Maison > Article > développement back-end > Quelles sont les causes des fuites de mémoire Golang ?
Les raisons de la fuite sont : 1. L'utilisation de time.After(). Chaque fois.After(duration x) générera NewTimer() Avant l'expiration de la durée x, la minuterie nouvellement créée ne sera pas GC. , GC; 2. Les ressources time.NewTicker ne sont pas libérées à temps ; 3. blocage de sélection ; 4. blocage de canal ; 5. application d'un trop grand nombre de goroutines, blocage de goroutines ;
L'environnement d'exploitation de ce tutoriel : système Windows 7, GO version 1.18, ordinateur Dell G3.
L'heure par défaut.After() a de la mémoire Le problème est divulgué car NewTimer() sera généré à chaque fois.After(duration
Au fil du temps, surtout si la durée Veuillez vérifier la différence par vous-même ou lire mes articles précédents https://blog.csdn.net/weixin_38299404/article/details/119352884
for true { select { case <-time.After(time.Minute * 3): // do something default: time.Sleep(time.Duration(1) * time.Second) } }
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.1 Causer le blocage de goroutine
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) } }La situation ci-dessus bloquera la consommation de ch3 et provoquer des fuites de mémoire
2.2 L'inactivité de la boucle provoque une surtension du processeur
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) } }Ci-dessus Une fois que la condition de la boucle for atteint la valeur par défaut, la boucle deviendra inactive et finira par faire monter en flèche le processeur
3.
Le blocage des canaux est principalement divisé en deux situations : le blocage en écriture et le blocage en lecturefunc 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) }Blocage en écriture
Le blocage du canal sans tampon est généralement l'opération d'écriture est bloquée car il n'y a pas de lecture
func channelTest() { //声明未初始化的channel读写都会阻塞 var c chan int //向channel中写数据 go func() { c <- 1 fmt.Println("g1 send succeed") time.Sleep(1 * time.Second) }() //从channel中读数据 go func() { <-c fmt.Println("g2 receive succeed") time.Sleep(1 * time.Second) }() time.Sleep(10 * time.Second) }
func channelTest() { var c = make(chan int) //10个协程向channel中写数据 for i := 0; i < 10; i++ { go func() { <- c fmt.Println("g1 receive succeed") time.Sleep(1 * time.Second) }() } //1个协程丛channel读数据 go func() { c <- 1 fmt.Println("g2 send succeed") time.Sleep(1 * time.Second) }() //会有写的9个协程阻塞得不到释放 time.Sleep(10 * time.Second) }
func channelTest() { var c = make(chan int, 8) //10个协程向channel中写数据 for i := 0; i < 10; i++ { go func() { <- c fmt.Println("g1 receive succeed") time.Sleep(1 * time.Second) }() } //1个协程丛channel读数据 go func() { c <- 1 fmt.Println("g2 send succeed") time.Sleep(1 * time.Second) }() //会有写的几个协程阻塞写不进去 time.Sleep(10 * time.Second) }
func channelTest() { var c = make(chan int) //1个协程向channel中写数据 go func() { <- c fmt.Println("g1 receive succeed") time.Sleep(1 * time.Second) }() //10个协程丛channel读数据 for i := 0; i < 10; i++ { go func() { c <- 1 fmt.Println("g2 send succeed") time.Sleep(1 * time.Second) }() } //会有读的9个协程阻塞得不到释放 time.Sleep(10 * time.Second) }4.2.3 Deadlock
//协程拿到锁未释放,其他协程获取锁会阻塞 func mutexTest() { mutex := sync.Mutex{} for i := 0; i < 10; i++ { go func() { mutex.Lock() fmt.Printf("%d goroutine get mutex", i) //模拟实际开发中的操作耗时 time.Sleep(100 * time.Millisecond) }() } time.Sleep(10 * time.Second) }4.2.4 Utilisation inappropriée du groupe d'attente
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") }() //其余协程获取锁都会失败 go func() { m1.Lock() fmt.Println("g3 get m1") }() time.Sleep(10 * time.Second) }
6. Transfert de valeur des tableaux
Étant donné que les tableaux sont le type de données de base de Golang, chaque tableau occupe un espace mémoire différent et le cycle de vie n'interfère pas les uns avec les autres. fuite, mais en tant que tableau Lors du transfert des paramètres formels, suivez la copie de la valeur temporelle. Si la fonction est appelée par plusieurs goroutines et que le tableau est trop grand, cela entraînera une augmentation de l'utilisation de la mémoire.var a []int func test(b []int) { a = b[:3] return }Par conséquent, les tranches ou les pointeurs sont généralement utilisés pour transférer de grands tableaux dans des scénarios de paramètres formels afin d'éviter une augmentation à court terme de l'utilisation de la mémoire.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!