溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

go內(nèi)存是怎么分配的

發(fā)布時間:2021-07-08 17:39:47 來源:億速云 閱讀:332 作者:chen 欄目:編程語言

本篇內(nèi)容主要講解“go內(nèi)存是怎么分配的”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“go內(nèi)存是怎么分配的”吧!

 

內(nèi)存分配器

程序中的數(shù)據(jù)和變量會被分配到程序的虛擬內(nèi)存中,內(nèi)存空間包含兩個重要的區(qū)域:堆(Heap)和棧(Stack)。函數(shù)調(diào)用的參數(shù)、返回值以及局部變量大都會被分配到棧上,這部分內(nèi)存會由編譯器進(jìn)行管理。不同的語言使用不同的方法管理堆區(qū)內(nèi)存,c語言中,需要主動申請和釋放內(nèi)存,在java中和go中基本上都交由編譯器管理,堆中的對象由內(nèi)存分配器分配以及垃圾回收器

 

原理

內(nèi)存管理一般包含三個不同的組件,分別是Mutator(用戶程序)、Allocator(分配器)、Collector(收集器)。當(dāng)用戶程序申請內(nèi)存時,會通過內(nèi)存分配器申請新內(nèi)存,而分配器會負(fù)責(zé)從堆中初始化相應(yīng)的內(nèi)存區(qū)域。

 

分配分發(fā)

內(nèi)存分配器一般包含兩種分配方法

  • Sequential Allocator,Bump Allocato (線性分配器)
  • Free-List Allocator (空閑鏈表分配器)
 
線性分配器

這是一種高效的內(nèi)存分配方法,但是局限性比較大。只需要在內(nèi)存中維護(hù)一個指向內(nèi)存特定位置的指針,如果申請內(nèi)存,分配器只需要檢查剩余的空閑內(nèi)存、返回分配的內(nèi)存區(qū)域并修改指針在內(nèi)存中的位置。

雖然這種方式擁有較快的執(zhí)行速度以及角度的實現(xiàn)復(fù)雜度,但是無法在內(nèi)存被釋放時重用內(nèi)存。

通常情況下需要與合適的垃圾回收算法配合使用,例如 標(biāo)記壓縮(Mark-Compact)、復(fù)制回收(Copying GC)和分代回收(Generational GC)等算法。它們可以通過拷貝的方式整理存活對象的碎片,定期合并空閑內(nèi)存,提升分配器的性能

 
空閑鏈表分配器

這種方法可以重用已經(jīng)被釋放的內(nèi)存,它在內(nèi)部維護(hù)一個類似鏈表的數(shù)據(jù)結(jié)構(gòu)。當(dāng)申請內(nèi)存時,空閑鏈表會一次遍歷空閑的內(nèi)存塊,找到足夠大的內(nèi)存,然后申請新的資源并且修改鏈表

常見的空閑鏈表分配器的策略有

  • 首次適應(yīng)  從表頭開始遍歷,選擇第一個大小大于申請內(nèi)存的內(nèi)存塊
  • 循環(huán)首次適應(yīng) 從上次遍歷的技術(shù)位置開始遍歷,選擇第一個大小大于申請內(nèi)存的內(nèi)存塊
  • 最優(yōu)適應(yīng)  從表頭開始遍歷,選擇最合適的內(nèi)存塊
  • 隔離適應(yīng) 將內(nèi)存分隔成多個鏈表,每個鏈表中的內(nèi)存塊大小相同,申請內(nèi)存時先找到滿足調(diào)價你的鏈表,再從鏈表中選擇合適的內(nèi)存塊
 
對象大小

在go語言中的內(nèi)存分配器會基于分配的內(nèi)存大小選擇不同的處理邏輯,運行時根據(jù)對象的大下將對象分成微對象、小對象和大對象三種

類別大小
微對象(0,16B)
小對象[16B,32KB]
大對象(32KB,+∞)

因為大多數(shù)情況下對象的大小都在32KB以下,而申請的內(nèi)存大小影響Go語言運行時分配內(nèi)存的過程和開銷,所以分別處理大對象和小對象有利于提高內(nèi)存分配器的性能。

 
多級緩存

內(nèi)存分配器不僅會區(qū)別對待大小不同的對象,還會將內(nèi)存分成不同的級別分別管理,TCMalloc和Go運行時分配器都會引入Thread Cache(線程緩存)、Central Cache(中心緩存)和Page Heap(頁堆)三個組件分級管理內(nèi)存

線程緩存屬于每一個的獨立的線程,它能夠滿足線程上絕大多數(shù)的內(nèi)存分配需求,因為不涉及多線程,所以也不需要使用互斥鎖來保護(hù)內(nèi)存,能夠減少鎖競爭帶來的性能損耗。當(dāng)線程緩存不能滿足需求時,運行時會使用中心緩存作為補(bǔ)充解決小對象的內(nèi)存分配,在遇到32KB以上的對象時,內(nèi)存分配器會選擇頁堆直接分配大內(nèi)存。

這種多層級的內(nèi)存分配設(shè)計與計算機(jī)操作系統(tǒng)中的多級緩存有些類似,因為多數(shù)的對象都是小對象,我們可以通過線程緩存和中心緩存提供足夠的內(nèi)存空間,發(fā)現(xiàn)資源不足時從上一級組件中獲取更多的內(nèi)存資源。

 
虛擬內(nèi)存布局

在Go1.11版本之后,使用了稀疏的堆內(nèi)存空間替代了連續(xù)的內(nèi)存,解決了連續(xù)內(nèi)存帶來的限制以及在特殊場景下可能出現(xiàn)的問題。

 
地址空間

因為所有的內(nèi)存最終都是要從操作系統(tǒng)中申請的,所以 Go 語言的運行時構(gòu)建了操作系統(tǒng)的內(nèi)存管理抽象層,該抽象層將運行時管理的地址空間分成以下四種狀態(tài)

狀態(tài)解釋
None內(nèi)存沒有被保存或者映射,是地址空間的默認(rèn)狀態(tài)
Reserved運行時持有該地址空間,但是訪問該內(nèi)存會導(dǎo)致錯誤
Prepared內(nèi)存被保留,一般沒有對應(yīng)的物理內(nèi)存訪問該片內(nèi)存的行為是未定義的可以快速轉(zhuǎn)到Ready狀態(tài)
Ready可以被安全訪問

到此,相信大家對“go內(nèi)存是怎么分配的”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

go
AI