Apakah punca kebocoran memori golang?

青灯夜游
Lepaskan: 2023-01-10 17:45:48
asal
2329 orang telah melayarinya

Sebab kebocoran adalah: 1. Penggunaan masa.Selepas(setiap kali.Selepas(tempoh x) akan menjana NewTimer() Sebelum tempoh x tamat, pemasa yang baru dibuat tidak akan GC , GC hanya akan berlaku selepas tamat tempoh. Sumber NewTicker tidak dikeluarkan dalam masa;

Apakah punca kebocoran memori golang?

Persekitaran pengendalian tutorial ini: sistem Windows 7, GO versi 1.18, komputer Dell G3.

Beberapa situasi di mana golang boleh menyebabkan kebocoran ingatan dengan mudah

1. Penggunaan pemasa yang tidak betul

1.1 Penggunaan masa.After()

Masa lalai.After() mempunyai masalah kebocoran memori, kerana setiap kali.After(tempoh x) akan menjana NewTimer( ), pemasa yang baru dibuat tidak akan GCed sebelum tempoh x tamat, dan hanya akan GCed selepas tamat tempoh.

Semakin masa berlalu, terutamanya jika tempoh Kaedah alternatif secara aktif mengeluarkan sumber Sila semak perbezaan antara kedua-duanya sendiri atau baca artikel saya sebelum ini 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)
	}
}
Salin selepas log masuk

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)
	}
}
Salin selepas log masuk

1.2 kali.Sumber NewTicker tidak dikeluarkan dalam masaApabila menggunakan masa.NewTicker, anda perlu secara manual panggil kaedah Stop() untuk melepaskan sumber, jika tidak, ia akan menyebabkan kebocoran memori kekal

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)
	}
}
Salin selepas log masuk

2 Apabila menggunakan pilih, jika terdapat kes yang tidak meliputi keadaan sepenuhnya dan tiada cawangan lalai untuk diproses, ia akhirnya akan menyebabkan kegagalan memori Kebocoran

2.1 Situasi yang membawa kepada penyekatan goroutine

Situasi di atas akan menyekat penggunaan ch3 dan menyebabkan kebocoran memori

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)
    }
}
Salin selepas log masuk
2.2 Loop melahu menyebabkan lonjakan CPU

Apabila keadaan gelung di atas mencecah lalai, melahu gelung akan berlaku, dan akhirnya CPU akan Meningkat

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)
}
Salin selepas log masuk
3 menyekat

Menyekat saluran terbahagi terutamanya kepada menyekat tulis dan menyekat bacaSaluran kosong

Menyekat tulis

menyekat saluran yang tidak dibuffer biasanya merupakan operasi menulis yang menyekat kerana tiada bacaan

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)
}
Salin selepas log masuk

  • Saluran penimbal disekat kerana penimbal penuh disekat
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)
}
Salin selepas log masuk

Bacaan disekat
  • Mengharapkan untuk membaca data daripada saluran, hasilnya tiada data Tulis goroutine dalam
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)
}
Salin selepas log masuk

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)
}
Salin selepas log masuk

4. Kebocoran memori disebabkan oleh goroutine

4.1 Memohon untuk terlalu banyak goroutine

Sebagai contoh, memohon terlalu banyak goroutine dalam gelung for dan tidak melepaskannya tepat pada masanya membawa kepada kebocoran ingatan

4.2 Penyekatan Goroutine

4.2.1 Masalah I/OSambungan I/O tidak mempunyai set tamat masa, menyebabkan goroutine terus menunggu dan kod akan meneruskan blok.

4.2.2 Kunci Mutex tidak dilepaskan

goroutine tidak boleh mendapatkan sumber kunci, menyebabkan goroutine disekat

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)
}
Salin selepas log masuk
Apabila program buntu, goroutine lain juga akan menyekat

4.2.4 Penggunaan kumpulan tunggu yang tidak betul

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)
}
Salin selepas log masuk
Ketakpadanan dalam bilangan Tambah, Selesai dan tunggu dalam kumpulan tunggu akan menyebabkan menunggu terus menunggu
5. Kebocoran memori disebabkan oleh hirisan

Apabila dua keratan berkongsi alamat, satu daripadanya ialah pembolehubah global, yang satu lagi tidak boleh menjadi GC; belum dibersihkan.

6 Pemindahan nilai tatasusunan

Memandangkan tatasusunan ialah jenis data asas Golang, setiap tatasusunan menduduki jumlah memori yang berbeza space. , kitaran hayat tidak mengganggu satu sama lain, dan sukar untuk menyebabkan kebocoran memori Walau bagaimanapun, apabila tatasusunan dihantar sebagai parameter formal, salinan nilai masa diikuti Jika fungsi dipanggil oleh berbilang goroutine tatasusunan terlalu besar, ia akan menyebabkan lonjakan penggunaan memori.
var a []int
 
func test(b []int) {
        a = b[:3]
        return
}
Salin selepas log masuk

Oleh itu, kepingan atau penunjuk biasanya digunakan untuk memindahkan tatasusunan besar dalam senario parameter formal untuk mengelakkan lonjakan jangka pendek dalam penggunaan memori [Cadangan berkaitan: Pergi video Tutorial

,

Pengajaran Pengaturcaraan

]
//统计nums中target出现的次数
func countTarget(nums [1000000]int, target int) int {
    num := 0
    for i := 0; i < len(nums) && nums[i] == target; i++ {
        num++
    }
    return num
}
Salin selepas log masuk

Atas ialah kandungan terperinci Apakah punca kebocoran memori golang?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Label berkaitan:
sumber:php.cn
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan