在Go語言中,當(dāng)一個(gè)變量在函數(shù)內(nèi)部被分配的時(shí)候,該變量要么被分配在棧上,要么被分配在堆上。如果一個(gè)變量被分配在棧上,那么它的生命周期將在函數(shù)調(diào)用結(jié)束后終止,當(dāng)函數(shù)返回時(shí),棧上的內(nèi)存將被自動(dòng)釋放。而如果一個(gè)變量被分配在堆上,那么它的生命周期將不會(huì)受到函數(shù)調(diào)用的影響,需要手動(dòng)釋放內(nèi)存。
當(dāng)一個(gè)變量的生命周期超過了它所在函數(shù)的作用域,即該變量需要在函數(shù)外部使用時(shí),它就會(huì)發(fā)生內(nèi)存逃逸,被分配在堆上。以下是一些常見的內(nèi)存逃逸場景:
返回指針:當(dāng)函數(shù)返回一個(gè)指針類型的變量時(shí),這個(gè)變量在函數(shù)外部仍然可以使用,因此會(huì)被分配在堆上。
閉包引用:當(dāng)一個(gè)閉包引用了函數(shù)外部的變量時(shí),這個(gè)變量的生命周期會(huì)延長到閉包結(jié)束,因此會(huì)被分配在堆上。
數(shù)組切片的擴(kuò)容:當(dāng)一個(gè)數(shù)組切片的容量不足時(shí),會(huì)進(jìn)行擴(kuò)容操作,將原有的元素復(fù)制到新的內(nèi)存空間中,因此原來的數(shù)組切片會(huì)被分配在堆上。
參數(shù)接收者是指針:當(dāng)一個(gè)方法的接收者是指針類型時(shí),該方法可以修改接收者指向的內(nèi)存,因此該接收者會(huì)被分配在堆上。
使用go關(guān)鍵字創(chuàng)建goroutine:當(dāng)使用go關(guān)鍵字創(chuàng)建一個(gè)goroutine時(shí),需要將被調(diào)用的函數(shù)以及其參數(shù)復(fù)制到新的goroutine的棧中,因此函數(shù)與參數(shù)會(huì)被分配在堆上。
這些場景下的變量會(huì)被分配在堆上,需要手動(dòng)釋放內(nèi)存,否則可能會(huì)導(dǎo)致內(nèi)存泄漏。同時(shí),內(nèi)存逃逸也會(huì)帶來一定的性能開銷,因?yàn)槎焉系膬?nèi)存分配和釋放需要額外的時(shí)間和空間。因此,在編寫Go代碼時(shí),應(yīng)盡量避免內(nèi)存逃逸的發(fā)生,以提高代碼的效率和性能。