What are the causes of golang memory leaks?
The reasons for the leak are: 1. The use of time.After(). Each time.After(duration x) will generate NewTimer(). Before duration x expires, the newly created timer will not be GC , GC will only occur after expiration; 2. time.NewTicker resources are not released in time; 3. select blocking; 4. channel blocking; 5. applying for too many goroutines, goroutine blocking; 6. caused by slice, etc.
The operating environment of this tutorial: Windows 7 system, GO version 1.18, Dell G3 computer.
Several situations in which golang can easily lead to memory leaks
1. Improper use of timers
1.1 The use of time.After()
The default time.After() will have a memory leak problem, because each time.After(duration x) will generate NewTimer( ), the newly created timer will not be GCed before duration x expires, and will only be GCed after expiration.
As time goes by, especially if the duration The method actively releases resources. Please check the difference between the two by yourself or read my previous articles 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 resources are not released in timeWhen using time.NewTicker, you need to manually call the Stop() method to release resources, otherwise it will cause a permanent memory leak
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 blockingWhen using select, if there is a case that does not fully cover the situation and there is no default branch for processing, it will eventually lead to memory leaks
2.1 Situations that cause goroutine to blocktimer := 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)
}
}
Copy after loginThe above situation will block the consumption of ch3 and cause memory leaks
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 Loop idling causes CPU surgefunc 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)
}
}
Copy after loginOnce the above for loop condition hits default, loop idling will occur, which will eventually lead to CPU surge
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. Channel blockingChannel blocking is mainly divided into two situations: write blocking and read blocking
Empty channel
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) }
Write blocking
The blocking of unbuffered channel is usually that the write operation blocks because there is no read.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) }
Copy after login
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) }
Copy after loginread blocked
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) }
Copy after login
4. Memory leak caused by goroutine
4.1 Apply for too many goroutines
For example, applying for too many goroutines in a for loop and not releasing them in time leads to memory leaks
##4.2 Goroutine blocking4.2. 1 I/O problem
The I/O connection does not set a timeout, causing the goroutine to keep waiting and the code to keep blocking.
4.2.2 The mutex lock is not releasedgoroutine cannot obtain the lock resource, causing goroutine to blockfunc 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)
}
Copy after login
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 DeadlockWhen the program deadlocks, other goroutines will also block//协程拿到锁未释放,其他协程获取锁会阻塞
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)
}
Copy after login
//协程拿到锁未释放,其他协程获取锁会阻塞 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 Improper use of waitgroupThe mismatch in the number of Add, Done and wait of waitgroup will cause wait to keep waiting
5. Memory caused by slice LeakWhen two slices share an address, one of which is a global variable, the other cannot be GC;
It has been used after appending the slice without cleaning it.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. Array value transferSince arrays are the basic data type of Golang, each array occupies a different amount of memory space. The cycles do not interfere with each other, so it is difficult to cause memory leaks. However, when the array is transmitted as a formal parameter, the time value copy is followed. If the function is called by multiple goroutines and the array is too large, it will cause a surge in memory usage. var a []int
func test(b []int) {
a = b[:3]
return
}
Copy after login Therefore, when large arrays are placed in formal parameter scenarios, slices or pointers are usually used to pass them to avoid a short-term surge in memory usage.
[Related recommendations: var a []int func test(b []int) { a = b[:3] return }
Go video tutorial
、Programming teaching】
The above is the detailed content of What are the causes of golang memory leaks?. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics



Queue threading problem in Go crawler Colly explores the problem of using the Colly crawler library in Go language, developers often encounter problems with threads and request queues. �...

The library used for floating-point number operation in Go language introduces how to ensure the accuracy is...

What should I do if the custom structure labels in GoLand are not displayed? When using GoLand for Go language development, many developers will encounter custom structure tags...

The difference between string printing in Go language: The difference in the effect of using Println and string() functions is in Go...

Which libraries in Go are developed by large companies or well-known open source projects? When programming in Go, developers often encounter some common needs, ...

The problem of using RedisStream to implement message queues in Go language is using Go language and Redis...

Two ways to define structures in Go language: the difference between var and type keywords. When defining structures, Go language often sees two different ways of writing: First...

Efficiently handle concurrency security issues in multi-process log writing. Multiple processes write the same log file at the same time. How to ensure concurrency is safe and efficient? This is a...
