Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Apakah punca kebocoran memori golang?

Apakah punca kebocoran memori golang?

青灯夜游
青灯夜游asal
2023-01-10 17:45:482244semak imbas

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)
	}
}

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)
	}
}

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)
	}
}

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)
    }
}
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)
}
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)
}

  • 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)
}

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)
}

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. 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)
}
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)
}
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
}

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
}

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

Kenyataan:
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