iOS記憶體管理和malloc原始碼解讀

2021-09-23 15:41:57 字數 2086 閱讀 2817

在接觸ios開發的時候,我們都知道「引用計數」的概念,也知道arc和mrr,但其實這僅僅是對堆記憶體上物件的記憶體管理。用wwdc某session裡的話說,這其實只是記憶體管理的冰山一角。

一般的iphone實際物理記憶體都在1g左右,對於超大的記憶體需求怎麼辦?其實也是和其它作業系統一樣的,都是由系統核心維護一套虛擬記憶體系統。這裡需要注意的是ios的虛存系統原則略有不同,最截然不同的地方是當物理記憶體緊張時的處理。

如上所述,ios在外存沒有交換區,沒有記憶體頁換出的過程。

通常,我們會在需要新物件的時候,進行[nsobject alloc]呼叫,而釋放物件時需要release(arc會自動做到這些)。

從蘋果公開的malloc原始碼上來看,malloc的原理大致如下:

malloc記憶體分配基於malloc zone,並將記憶體分配按大小分為nano、tiny、small、large幾種型別,申請時按需進行最適分配

malloc在首次呼叫時,初始化default zone,在64位情況下,會初始化default zone為nano zone,同時初始化乙個scalable zone作為helper zone,nano zone負責nano大小的分配,scalable zone則負責tiny、small和large記憶體的分配

每次malloc時,根據傳入的size引數,優先交給nano zone做分配處理,如果大小不在nano範圍,則轉交給helper zone處理。

(截圖自

下面分別對nano zone和scalable zone上分配記憶體的原始碼做簡要解讀(由於蘋果open source的**是針對os x的特定版本,具體細節可能與ios上有所不同,如位址空間分布)。

在支援64位的條件按下,malloc優先考慮nano malloc,負責對256b以下小記憶體分配,單位是16b。

nano zone分配記憶體的位址空間範圍是0x00006nnnnnnnnnnn(osx上64位情況),將位址空間從大到小一次分為magazine、band和slot幾個級別。

分配過程:

其實從快取獲取空餘記憶體和釋放記憶體時都會對指向這篇記憶體區域的指標進行檢查,如果有類似位址不對齊、未釋放/多次釋放、所屬位址與預期的mag、slot不匹配等情況都會以報錯結束。

下圖是我根據個人理解梳理出來的乙個關係圖,圖中標出了nanozone_t、meta_data_t等相關結構的關鍵字段畫了出來(osx)。

除了分配和釋放,系統記憶體吃緊時,nano zone需將cache的記憶體區塊還給系統,這主要是通過對各個slot對應的meta data上掛著的空閒鍊錶上記憶體區塊**來完成。

對於超出nano大小範圍或者不支援nano分配的,直接會在scalable zone(下文簡稱szone)上分配記憶體。由於szone上的記憶體分配比起nano分配要較為複雜,細節繁多,下面僅作簡要介紹,感興趣的同學可以直接閱讀原始碼。

在szone上分配的記憶體包括tiny、small和large三大類,其中tiny和small的分配、釋放過程大致相同,large型別有自己的方式管理。

而tiny、small的方式也依然遵循nano分配中的原則,新記憶體從系統申請並分配,free後按照大小以特定的形式快取起來,供後續分配使用。這裡的分配在region上進行,region和nano malloc裡的band概念極為相似,但不同的是位址空間未必連續,而且每個region都有自己的點陣圖等描述資訊。和nano,一樣每個cpu有乙個magazine,除此之外還分配了乙個index為-1的magazine作為後備之用。

下面是乙個簡圖。

以tiny的情況為例,分配時:

free時:

而large的情況,malloc以頁為單位申請和分配記憶體,不區分magazine,szone統一維護乙個hash table管理已申請的記憶體。而且由於記憶體區域都比較龐大,只快取總量2g的區塊,分為16個元素,每個最大為128m。large相關的結構相對簡單,就不特意畫圖了。

iOS記憶體管理和malloc原始碼解讀

最近由於排查問題,順便對ios的記憶體管理,尤其是malloc庫稍微深入地了解一下,在這裡整理出來,和大家分享一下。在接觸ios開發的時候,我們都知道 引用計數 的概念,也知道arc和mrr,但其實這僅僅是對堆記憶體上物件的記憶體管理。用wwdc某session裡的話說,這其實只是記憶體管理的冰山一...

ios記憶體管理

引用計數 每個物件有乙個與之相關的整數,稱作 引用計數器 或者 保留計數器 當某段 需要訪問乙個物件時,該段 會將物件的保留計數器 1,表示需要訪問這個物件 當結束對該物件的訪問時,保留計數器 1,表示它不在訪問該物件 當保留計數器為0時,物件被銷毀,所佔記憶體被系統收回。當使用new retain...

iOS記憶體管理

前提 1 以下是針對cocoa物件,不包括core foundation 2 cocoa物件都是用引用計數來跟蹤物件的記憶體使用情況的。3 在子類裡面父類先初始化和後釋放的原則。自己想下為什麼 棧空間和堆空間的區別。我們說的記憶體管理都是基於堆空間的,因為函式內的棧空間是由編譯器自己控制的。關於co...