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.
Plusieurs situations où Golang peut facilement entraîner des fuites de mémoire
1. Utilisation inappropriée des minuteries
1.1 L'utilisation de time.After()
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) } }
1.2 time.NewTicker ressources ne sont pas libérés à tempslors de l'utilisation de time.NewTicker Vous devez appeler manuellement la méthode Stop() pour libérer les ressources, sinon cela provoquera une fuite de mémoire permanente
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, s'il y a un cas qui n'est pas entièrement couvert et qu'il n'y a pas de branche par défaut pour le traitement, cela finira par entraîner des fuites de mémoire
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)
}
}
Copier après la connexionLa situation ci-dessus bloquera la consommation de ch3 et provoquer des fuites de mémoire
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.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)
}
}
Copier après la connexionCi-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
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) } }
3.
Le blocage des canaux est principalement divisé en deux situations : le blocage en écriture et le blocage en lecturecanal videfunc 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)
}
Copier après la connexion Blocage en écriture
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) }
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) }
- Le canal tamponné est bloqué car le tampon est plein, l'opération d'écriture est bloquée
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) }
- J'attends avec impatience la lecture des données du canal, le résultat est qu'il n'y a pas de goroutine pour écrire des données
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) }
4. Fuite de mémoire causée par goroutine
4.1 Demander trop de goroutines
Par exemple, dans une boucle for Trop de goroutines ne sont pas libérées à temps, provoquant des fuites de mémoire
4.2 Blocage de Goroutine
4.2.1 Problème d'E/SLa connexion d'E/S ne définit pas de délai d'attente, ce qui oblige la goroutine à attendre et le code continuera à se bloquer.
4.2.2 Le verrou mutex n'est pas libéré
goroutine ne peut pas obtenir la ressource de verrouillage, ce qui provoque le blocage de la goroutinefunc 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)
}
Copier après la connexion4.2.3 Deadlock
Lorsque le programme se bloque, d'autres goroutines le feront bloque également 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) }
//协程拿到锁未释放,其他协程获取锁会阻塞
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)
}
Copier après la connexion4.2.4 Utilisation inappropriée du groupe d'attente
La différence entre le nombre d'ajout, terminé et d'attente du groupe d'attente entraînera une attente constante//协程拿到锁未释放,其他协程获取锁会阻塞 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) }
5. par slice
Lorsque deux tranches sont partagées, dont l'une est une variable globale, l'autre ne peut pas être GCElle a été utilisée après l'ajout de la tranche et n'a pas été nettoyée. 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)
}
Copier après la connexion
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
}
Copier après la connexion 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.
var a []int func test(b []int) { a = b[:3] return }
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!

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Problème de threading de file d'attente dans Go Crawler Colly explore le problème de l'utilisation de la bibliothèque Crawler Crawler dans le langage Go, les développeurs rencontrent souvent des problèmes avec les threads et les files d'attente de demande. � ...

La bibliothèque utilisée pour le fonctionnement du numéro de point flottante dans le langage go présente comment s'assurer que la précision est ...

Que dois-je faire si les étiquettes de structure personnalisées à Goland ne sont pas affichées? Lorsque vous utilisez Goland pour le développement du langage GO, de nombreux développeurs rencontreront des balises de structure personnalisées ...

La différence entre l'impression de chaîne dans le langage go: la différence dans l'effet de l'utilisation de fonctions println et string () est en Go ...

Quelles bibliothèques de GO sont développées par de grandes entreprises ou des projets open source bien connus? Lors de la programmation en Go, les développeurs rencontrent souvent des besoins communs, ...

Le problème de l'utilisation de Redessstream pour implémenter les files d'attente de messages dans le langage GO consiste à utiliser le langage GO et redis ...

Deux façons de définir les structures dans le langage GO: la différence entre les mots clés VAR et le type. Lorsque vous définissez des structures, GO Language voit souvent deux façons d'écrire différentes: d'abord ...

Gérez efficacement les problèmes de sécurité de la concurrence dans la rédaction de journaux multiproces. Plusieurs processus écrivent le même fichier journal en même temps. Comment s'assurer que la concurrence est sûre et efficace? C'est un ...
