亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

go語(yǔ)言?xún)?nèi)存泄漏的常見(jiàn)形式

 更新時(shí)間:2025年04月14日 08:33:33   作者:Achilles.Wang  
本文主要介紹了go語(yǔ)言?xún)?nèi)存泄漏的常見(jiàn)形式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

go語(yǔ)言?xún)?nèi)存泄漏

在這里插入圖片描述

子字符串導(dǎo)致的內(nèi)存泄漏

使用自動(dòng)垃圾回收的語(yǔ)言進(jìn)行編程時(shí),通常我們無(wú)需擔(dān)心內(nèi)存泄漏的問(wèn)題,因?yàn)檫\(yùn)行時(shí)會(huì)定期回收未使用的內(nèi)存。但是如果你以為這樣就完事大吉了,哪里就大錯(cuò)特措了。

因?yàn)?,雖然go中并未對(duì)字符串時(shí)候共享底層內(nèi)存塊進(jìn)行規(guī)定,但go語(yǔ)言編譯器/運(yùn)行時(shí)默認(rèn)情況下允許字符串共享底層內(nèi)存塊,直到原先的字符串指向的內(nèi)存被修改才會(huì)進(jìn)行寫(xiě)時(shí)復(fù)制,這是一個(gè)很好的設(shè)計(jì),既能節(jié)省內(nèi)存,又能節(jié)省CPU資源,但有時(shí)也會(huì)導(dǎo)致"內(nèi)存泄漏"。

例如如下代碼,一旦調(diào)用demo就會(huì)導(dǎo)致將近1M內(nèi)存的泄漏,因?yàn)閟0只使用了50字節(jié),但是會(huì)導(dǎo)致1M的內(nèi)存一直無(wú)法被回收,這些內(nèi)存會(huì)一直持續(xù)到下次s0被修改的時(shí)候才會(huì)被釋放掉。

var s0 string // a package-level variable

// A demo purpose function.
func f(s1 string) {
	s0 = s1[:50]
	// Now, s0 shares the same underlying memory block
	// with s1. Although s1 is not alive now, but s0
	// is still alive, so the memory block they share
	// couldn't be collected, though there are only 50
	// bytes used in the block and all other bytes in
	// the block become unavailable.
}

func demo() {
	s := createStringWithLengthOnHeap(1 << 20) // 1M bytes
	f(s)
}

為了避免這種內(nèi)存泄漏,我們可以使用[]byte來(lái)替代原先的1M大小的內(nèi)存,不過(guò)這樣會(huì)有兩次50字節(jié)的內(nèi)存重復(fù)

func f(s1 string) {
	s0 = string([]byte(s1[:50]))
}

當(dāng)然我們也可以利用go編譯器的優(yōu)化來(lái)避免不必要的重復(fù),只需要浪費(fèi)一個(gè)字節(jié)內(nèi)存就行

func f(s1 string) {
	s0 = (" " + s1[:50])[1:]
}

上述方法的缺點(diǎn)是編譯器優(yōu)化以后可能會(huì)失效,并且其他編譯器可能無(wú)法提供該優(yōu)化

避免此類(lèi)內(nèi)存泄漏的第三種方法是利用 Go 1.10 以來(lái)支持的 strings.Builder 。

import "strings"

func f(s1 string) {
	var b strings.Builder
	b.Grow(50)
	b.WriteString(s1[:50])
	s0 = b.String()
}

從 Go 1.18 開(kāi)始, strings 標(biāo)準(zhǔn)庫(kù)包中新增了 Clone 函數(shù),這成為了完成這項(xiàng)工作的最佳方式。

子切片導(dǎo)致的內(nèi)存泄漏

同樣場(chǎng)景下,切片也會(huì)導(dǎo)致內(nèi)存的浪費(fèi)

與子字符串類(lèi)似,子切片也可能導(dǎo)致某種內(nèi)存泄漏。在下面的代碼中,調(diào)用 g 函數(shù)后,保存 s1 元素的內(nèi)存塊所占用的大部分內(nèi)存將會(huì)丟失(如果沒(méi)有其他值引用該內(nèi)存塊)。

var s0 []int

func g(s1 []int) {
	// Assume the length of s1 is much larger than 30.
	s0 = s1[len(s1)-30:]
}

如果我們想避免這種內(nèi)存泄漏,我們必須復(fù)制 s0 的 30 個(gè)元素,這樣 s0 的活躍性就不會(huì)阻止收集承載 s1 元素的內(nèi)存塊。

func g(s1 []int) {
	s0 = make([]int, 30)
	copy(s0, s1[len(s1)-30:])
	// Now, the memory block hosting the elements
	// of s1 can be collected if no other values
	// are referencing the memory block.
}

未重置子切片指針導(dǎo)致的內(nèi)存泄漏

在下面的代碼中,調(diào)用 h 函數(shù)后,為切片 s 的第一個(gè)和最后一個(gè)元素分配的內(nèi)存塊將丟失。

func h() []*int {
	s := []*int{new(int), new(int), new(int), new(int)}
	// do something with s ...
	// 返回一個(gè)從1開(kāi)始,不能到索引3的新切片, 也就是 s[1], s[2]
	return s[1:3:3]
}

只要返回的切片仍然有效,它就會(huì)阻止收集 s 的任何元素,從而阻止收集為 s 的第一個(gè)和最后一個(gè)元素引用的兩個(gè) int 值分配的兩個(gè)內(nèi)存塊。

如果我們想避免這種內(nèi)存泄漏,我們必須重置丟失元素中存儲(chǔ)的指針。

func h() []*int {
	s := []*int{new(int), new(int), new(int), new(int)}
	// do something with s ...

	// Reset pointer values.
	s[0], s[len(s)-1] = nil, nil
	return s[1:3:3]
}

掛起Goroutine導(dǎo)致的內(nèi)存泄漏

有時(shí),Go 程序中的某些 goroutine 可能會(huì)永遠(yuǎn)處于阻塞狀態(tài)。這樣的 goroutine 被稱(chēng)為掛起的 goroutine。Go 運(yùn)行時(shí)不會(huì)終止掛起的 goroutine,因此為掛起的 goroutine 分配的資源(以及它們引用的內(nèi)存塊)永遠(yuǎn)不會(huì)被垃圾回收。

Go 運(yùn)行時(shí)不會(huì)殺死掛起的 Goroutine 有兩個(gè)原因。一是 Go 運(yùn)行時(shí)有時(shí)很難判斷一個(gè)阻塞的 Goroutine 是否會(huì)被永久阻塞。二是我們有時(shí)會(huì)故意讓 Goroutine 掛起。例如,有時(shí)我們可能會(huì)讓 Go 程序的主 Goroutine 掛起,以避免程序退出。

如果不停止time.Ticker也會(huì)導(dǎo)致內(nèi)存泄漏

當(dāng) time.Timer 值不再使用時(shí),它會(huì)在一段時(shí)間后被垃圾回收。但 time.Ticker 值則不然。我們應(yīng)該在 time.Ticker 值不再使用時(shí)停止它。

不正確地使用終結(jié)器會(huì)導(dǎo)致真正的內(nèi)存泄漏

為屬于循環(huán)引用組的成員值設(shè)置終結(jié)器(finalizer)可能會(huì)阻止為該循環(huán)引用組分配的所有內(nèi)存塊被回收。這是真正的內(nèi)存泄漏,不是某種假象。

例如,在調(diào)用并退出以下函數(shù)后,分配給 x 和 y 的內(nèi)存塊不能保證在未來(lái)的垃圾收集中被收集。

func memoryLeaking() {
	type T struct {
		v [1<<20]int
		t *T
	}

	var finalizer = func(t *T) {
		 fmt.Println("finalizer called")
	}

	var x, y T

	// The SetFinalizer call makes x escape to heap.
	runtime.SetFinalizer(&x, finalizer)

	// The following line forms a cyclic reference
	// group with two members, x and y.
	// This causes x and y are not collectable.
	x.t, y.t = &y, &x // y also escapes to heap.
}

因此,請(qǐng)避免為循環(huán)引用組中的值設(shè)置終結(jié)器。

延遲函數(shù)調(diào)用導(dǎo)致的某種資源泄漏

非常大的延遲調(diào)用堆棧也可能會(huì)消耗大量?jī)?nèi)存,并且如果某些調(diào)用延遲太多,某些資源可能無(wú)法及時(shí)釋放。

例如,如果在調(diào)用以下函數(shù)時(shí)需要處理許多文件,那么在函數(shù)退出之前將有大量文件處理程序無(wú)法釋放。

func writeManyFiles(files []File) error {
	for _, file := range files {
		f, err := os.Open(file.path)
		if err != nil {
			return err
		}
		defer f.Close()

		_, err = f.WriteString(file.content)
		if err != nil {
			return err
		}

		err = f.Sync()
		if err != nil {
			return err
		}
	}

	return nil
}

對(duì)于這種情況,我們可以使用匿名函數(shù)來(lái)封裝延遲調(diào)用,以便延遲函數(shù)調(diào)用能夠更早地執(zhí)行。例如,上面的函數(shù)可以重寫(xiě)并改進(jìn)為

func writeManyFiles(files []File) error {
	for _, file := range files {
		if err := func() error {
			f, err := os.Open(file.path)
			if err != nil {
				return err
			}
			// The close method will be called at
			// the end of the current loop step.
			defer f.Close()

			_, err = f.WriteString(file.content)
			if err != nil {
				return err
			}

			return f.Sync()
		}(); err != nil {
			return err
		}
	}

	return nil
}

當(dāng)然不要犯以下錯(cuò)誤,需要有些同學(xué)將需要延時(shí)調(diào)用的函數(shù)字節(jié)省略,導(dǎo)致資源泄漏

_, err := os.Open(file.path)

如果是http請(qǐng)求,還會(huì)導(dǎo)致服務(wù)端擠壓大量的連接無(wú)法釋放

到此這篇關(guān)于go語(yǔ)言?xún)?nèi)存泄漏的常見(jiàn)形式的文章就介紹到這了,更多相關(guān)go語(yǔ)言?xún)?nèi)存泄漏內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go-RESTful實(shí)現(xiàn)下載功能思路詳解

    Go-RESTful實(shí)現(xiàn)下載功能思路詳解

    這篇文章主要介紹了Go-RESTful實(shí)現(xiàn)下載功能,文件下載包括文件系統(tǒng)IO和網(wǎng)絡(luò)IO,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-10-10
  • go語(yǔ)言實(shí)現(xiàn)依賴(lài)注入的示例代碼

    go語(yǔ)言實(shí)現(xiàn)依賴(lài)注入的示例代碼

    依賴(lài)注入和控制反轉(zhuǎn)恰恰相反,它是一種具體的編碼技巧,我們不通過(guò) new 的方式在類(lèi)內(nèi)部創(chuàng)建依賴(lài)類(lèi)的對(duì)象,而是將依賴(lài)的類(lèi)對(duì)象在外部創(chuàng)建好之后,通過(guò)構(gòu)造函數(shù)、函數(shù)參數(shù)等方式傳遞給類(lèi)來(lái)使用,本文將給大家介紹go語(yǔ)言實(shí)現(xiàn)依賴(lài)注入,需要的朋友可以參考下
    2024-01-01
  • 解決goland中編輯tpl文件不高亮沒(méi)智能補(bǔ)全的問(wèn)題

    解決goland中編輯tpl文件不高亮沒(méi)智能補(bǔ)全的問(wèn)題

    這篇文章主要介紹了解決goland中編輯tpl文件不高亮沒(méi)智能補(bǔ)全的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • Go語(yǔ)言中strings.HasPrefix、strings.Split、strings.SplitN()?函數(shù)

    Go語(yǔ)言中strings.HasPrefix、strings.Split、strings.SplitN()?函數(shù)

    本文主要介紹了Go語(yǔ)言中strings.HasPrefix、strings.Split、strings.SplitN()函數(shù),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-08-08
  • golang優(yōu)化目錄遍歷的實(shí)現(xiàn)方法

    golang優(yōu)化目錄遍歷的實(shí)現(xiàn)方法

    對(duì)于go1.16的新變化,大家印象最深的可能是io包的大規(guī)模重構(gòu),但這個(gè)重構(gòu)實(shí)際上還引進(jìn)了一個(gè)優(yōu)化,這篇文章要說(shuō)的就是這個(gè)優(yōu)化,所以本將給大家介紹golang是如何優(yōu)化目錄遍歷的,需要的朋友可以參考下
    2024-08-08
  • golang使用go test輸出單元測(cè)試覆蓋率的方式

    golang使用go test輸出單元測(cè)試覆蓋率的方式

    單元測(cè)試覆蓋率是衡量代碼質(zhì)量的一個(gè)重要指標(biāo),重要的代碼文件覆蓋率應(yīng)該至少達(dá)到80%以上,Java 可以通過(guò)JaCoCo 統(tǒng)計(jì)覆蓋率,那么go 項(xiàng)目如何進(jìn)行代碼覆蓋率測(cè)試呢,本文將給大家詳細(xì)的介紹一下golang使用go test輸出單元測(cè)試覆蓋率的方式,需要的朋友可以參考下
    2024-02-02
  • golang框架中跨服務(wù)的最佳通信協(xié)議和工具

    golang框架中跨服務(wù)的最佳通信協(xié)議和工具

    在 go 框架中實(shí)現(xiàn)跨服務(wù)通信的最佳實(shí)踐包括使用 grpc(適用于低延遲高吞吐量)、http 客戶(hù)端(適用于 restful api)和消息隊(duì)列(適用于異步解耦通信),在選擇通信方式時(shí),應(yīng)考慮服務(wù)交互模式、性能要求和部署環(huán)境等因素
    2024-06-06
  • 解析golang 標(biāo)準(zhǔn)庫(kù)template的代碼生成方法

    解析golang 標(biāo)準(zhǔn)庫(kù)template的代碼生成方法

    這個(gè)項(xiàng)目的自動(dòng)生成代碼都是基于 golang 的標(biāo)準(zhǔn)庫(kù) template 的,所以這篇文章也算是對(duì)使用 template 庫(kù)的一次總結(jié),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2021-11-11
  • GoLang職責(zé)鏈模式代碼實(shí)現(xiàn)介紹

    GoLang職責(zé)鏈模式代碼實(shí)現(xiàn)介紹

    這篇文章主要介紹了GoLang職責(zé)鏈模式代碼實(shí)現(xiàn),職責(zé)鏈模式是一種常用的設(shè)計(jì)模式,可以提高代碼的靈活性與可維護(hù)性,職責(zé)鏈模式將請(qǐng)求和處理分離,可以讓請(qǐng)求在處理鏈中依次經(jīng)過(guò)多個(gè)處理者,直到找到能夠處理請(qǐng)求的處理者為止
    2023-05-05
  • Go語(yǔ)言中常見(jiàn)的文件操作分享

    Go語(yǔ)言中常見(jiàn)的文件操作分享

    文件操作應(yīng)該是應(yīng)用程序里非常常見(jiàn)的一種操作,無(wú)論是哪種應(yīng)用場(chǎng)景,幾乎都離不開(kāi)文件的基本操作。Go語(yǔ)言中提供了三個(gè)不同的包去處理文件,下午就來(lái)說(shuō)說(shuō)它們的具體使用
    2023-01-01

最新評(píng)論