您好,登錄后才能下訂單哦!
本篇內容主要講解“go內存是怎么分配的”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“go內存是怎么分配的”吧!
程序中的數據和變量會被分配到程序的虛擬內存中,內存空間包含兩個重要的區域:堆(Heap)和棧(Stack)。函數調用的參數、返回值以及局部變量大都會被分配到棧上,這部分內存會由編譯器進行管理。不同的語言使用不同的方法管理堆區內存,c語言中,需要主動申請和釋放內存,在java中和go中基本上都交由編譯器管理,堆中的對象由內存分配器分配以及垃圾回收器
內存管理一般包含三個不同的組件,分別是Mutator(用戶程序)、Allocator(分配器)、Collector(收集器)。當用戶程序申請內存時,會通過內存分配器申請新內存,而分配器會負責從堆中初始化相應的內存區域。
內存分配器一般包含兩種分配方法
這是一種高效的內存分配方法,但是局限性比較大。只需要在內存中維護一個指向內存特定位置的指針,如果申請內存,分配器只需要檢查剩余的空閑內存、返回分配的內存區域并修改指針在內存中的位置。
雖然這種方式擁有較快的執行速度以及角度的實現復雜度,但是無法在內存被釋放時重用內存。
通常情況下需要與合適的垃圾回收算法配合使用,例如 標記壓縮(Mark-Compact)、復制回收(Copying GC)和分代回收(Generational GC)等算法。它們可以通過拷貝的方式整理存活對象的碎片,定期合并空閑內存,提升分配器的性能
這種方法可以重用已經被釋放的內存,它在內部維護一個類似鏈表的數據結構。當申請內存時,空閑鏈表會一次遍歷空閑的內存塊,找到足夠大的內存,然后申請新的資源并且修改鏈表
常見的空閑鏈表分配器的策略有
在go語言中的內存分配器會基于分配的內存大小選擇不同的處理邏輯,運行時根據對象的大下將對象分成微對象、小對象和大對象三種
類別 | 大小 |
---|---|
微對象 | (0,16B) |
小對象 | [16B,32KB] |
大對象 | (32KB,+∞) |
因為大多數情況下對象的大小都在32KB以下,而申請的內存大小影響Go語言運行時分配內存的過程和開銷,所以分別處理大對象和小對象有利于提高內存分配器的性能。
內存分配器不僅會區別對待大小不同的對象,還會將內存分成不同的級別分別管理,TCMalloc和Go運行時分配器都會引入Thread Cache(線程緩存)、Central Cache(中心緩存)和Page Heap(頁堆)三個組件分級管理內存
線程緩存屬于每一個的獨立的線程,它能夠滿足線程上絕大多數的內存分配需求,因為不涉及多線程,所以也不需要使用互斥鎖來保護內存,能夠減少鎖競爭帶來的性能損耗。當線程緩存不能滿足需求時,運行時會使用中心緩存作為補充解決小對象的內存分配,在遇到32KB以上的對象時,內存分配器會選擇頁堆直接分配大內存。
這種多層級的內存分配設計與計算機操作系統中的多級緩存有些類似,因為多數的對象都是小對象,我們可以通過線程緩存和中心緩存提供足夠的內存空間,發現資源不足時從上一級組件中獲取更多的內存資源。
在Go1.11版本之后,使用了稀疏的堆內存空間替代了連續的內存,解決了連續內存帶來的限制以及在特殊場景下可能出現的問題。
因為所有的內存最終都是要從操作系統中申請的,所以 Go 語言的運行時構建了操作系統的內存管理抽象層,該抽象層將運行時管理的地址空間分成以下四種狀態
狀態 | 解釋 |
---|---|
None | 內存沒有被保存或者映射,是地址空間的默認狀態 |
Reserved | 運行時持有該地址空間,但是訪問該內存會導致錯誤 |
Prepared | 內存被保留,一般沒有對應的物理內存訪問該片內存的行為是未定義的可以快速轉到Ready狀態 |
Ready | 可以被安全訪問 |
到此,相信大家對“go內存是怎么分配的”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。