最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

go語(yǔ)言內(nèi)存泄漏的常見形式

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

go語(yǔ)言內(nèi)存泄漏

在這里插入圖片描述

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

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

因?yàn)椋m然go中并未對(duì)字符串時(shí)候共享底層內(nèi)存塊進(jìn)行規(guī)定,但go語(yǔ)言編譯器/運(yùn)行時(shí)默認(rèn)情況下允許字符串共享底層內(nèi)存塊,直到原先的字符串指向的內(nèi)存被修改才會(huì)進(jìn)行寫時(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)化

避免此類內(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 開始, strings 標(biāo)準(zhǔn)庫(kù)包中新增了 Clone 函數(shù),這成為了完成這項(xiàng)工作的最佳方式。

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

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

與子字符串類似,子切片也可能導(dǎo)致某種內(nèi)存泄漏。在下面的代碼中,調(diào)用 g 函數(shù)后,保存 s1 元素的內(nèi)存塊所占用的大部分內(nèi)存將會(huì)丟失(如果沒有其他值引用該內(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開始,不能到索引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 被稱為掛起的 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ù)可以重寫并改進(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ǔ)言內(nèi)存泄漏的常見形式的文章就介紹到這了,更多相關(guān)go語(yǔ)言內(nèi)存泄漏內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • go-zero?rpc分布式微服務(wù)使用詳解

    go-zero?rpc分布式微服務(wù)使用詳解

    文章介紹了如何安裝Go環(huán)境、配置Go環(huán)境、安裝goctl工具以及創(chuàng)建第一個(gè)項(xiàng)目,詳細(xì)的步驟包括生成項(xiàng)目、配置文件、啟動(dòng)服務(wù)、測(cè)試項(xiàng)目等,文章還涵蓋了Go?Zero框架的基本概念,如API定義、服務(wù)間通信、業(yè)務(wù)邏輯實(shí)現(xiàn)等
    2026-01-01
  • Go語(yǔ)言正則表達(dá)式用法實(shí)例小結(jié)【查找、匹配、替換等】

    Go語(yǔ)言正則表達(dá)式用法實(shí)例小結(jié)【查找、匹配、替換等】

    這篇文章主要介紹了Go語(yǔ)言正則表達(dá)式用法,結(jié)合實(shí)例形式分析了Go語(yǔ)言基于正則實(shí)現(xiàn)查找、匹配、替換等基本操作的實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2017-01-01
  • win10下go mod配置方式

    win10下go mod配置方式

    這篇文章主要介紹了win10下go mod配置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-04-04
  • Golang 如何判斷數(shù)組某個(gè)元素是否存在 (isset)

    Golang 如何判斷數(shù)組某個(gè)元素是否存在 (isset)

    這篇文章主要介紹了Golang 如何判斷數(shù)組某個(gè)元素是否存在 (isset),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-04-04
  • Go基于struct?tag實(shí)現(xiàn)結(jié)構(gòu)體字段級(jí)別的訪問控制

    Go基于struct?tag實(shí)現(xiàn)結(jié)構(gòu)體字段級(jí)別的訪問控制

    本文將會(huì)基于這個(gè)主題展開,討論Go中的結(jié)構(gòu)體tag究竟是什么,我們?cè)撊绾卫盟?另外,文末還提供了一個(gè)實(shí)際案例,實(shí)現(xiàn)結(jié)構(gòu)體字段級(jí)別的訪問,幫助我們進(jìn)一步提升對(duì)struct tag的理解
    2024-02-02
  • Go計(jì)時(shí)器的示例代碼

    Go計(jì)時(shí)器的示例代碼

    定時(shí)器是任何編程語(yǔ)言的重要工具,它允許開發(fā)人員在特定時(shí)間間隔安排任務(wù)或執(zhí)行代碼,本文主要介紹了Go計(jì)時(shí)器的示例代碼,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01
  • Go 庫(kù)bytes.Buffer和strings.Builder使用及性能對(duì)比

    Go 庫(kù)bytes.Buffer和strings.Builder使用及性能對(duì)比

    這篇文章主要為大家介紹了Go 庫(kù)bytes.Buffer和strings.Builder使用及性能對(duì)比,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • Go語(yǔ)言實(shí)現(xiàn)生成樣式美觀的PDF文件

    Go語(yǔ)言實(shí)現(xiàn)生成樣式美觀的PDF文件

    使用?Go?語(yǔ)言生成樣式美觀的?PDF?文件是一個(gè)常見的需求,尤其是在報(bào)告生成、發(fā)票、合同等場(chǎng)景中,下面就跟隨小編一起來(lái)學(xué)習(xí)一下具體實(shí)現(xiàn)方法吧
    2025-01-01
  • 一篇文章讓你學(xué)會(huì)Go語(yǔ)言循環(huán)語(yǔ)句

    一篇文章讓你學(xué)會(huì)Go語(yǔ)言循環(huán)語(yǔ)句

    在Go語(yǔ)言中循環(huán)語(yǔ)句用于重復(fù)執(zhí)行一段代碼,直到滿足特定的條件為止,這篇文章主要介紹了Go語(yǔ)言循環(huán)語(yǔ)句的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-11-11
  • Golang發(fā)送http GET請(qǐng)求的示例代碼

    Golang發(fā)送http GET請(qǐng)求的示例代碼

    這篇文章主要介紹了Golang發(fā)送http GET請(qǐng)求的示例代碼,幫助大家更好的理解和使用golang,感興趣的朋友可以了解下
    2020-12-12

最新評(píng)論

罗定市| 通化县| 金湖县| 洪湖市| 无极县| 张北县| 拜城县| 繁昌县| 都匀市| 繁昌县| 绿春县| 邵阳县| 西乌珠穆沁旗| 通州市| 烟台市| 民乐县| 昌都县| 天全县| 庄河市| 公主岭市| 黄浦区| 贵定县| 洛隆县| 凤冈县| 贵南县| 海城市| 章丘市| 平潭县| 安岳县| 睢宁县| 依安县| 嘉兴市| 宝清县| 尼木县| 宁河县| 体育| 平陆县| 和田县| 镇康县| 武冈市| 锡林浩特市|