ios系統下的記憶體布局
最上面是核心區,最下面是保留區,中間是給程式載入的空間。
從高位址到低位址依次為核心區、棧、堆、靜態全域性區(未初始化區域.bss和已初始化區域.data)、**區、保留區;
程式被載入到記憶體分成三段未初始化資料(.bss)、已初始化資料(.data)和**段(.text)。
**段顧名思義存放**;
已初始化區域:已經初始化宣告的靜態變數和全域性變數;
未初始化區域:未初始化的靜態變數和全域性變數;
堆heap:建立的物件或被copy的block;
記憶體管理方案
ios管理系統針對不同的場景提供不同的記憶體管理方案。
·taggedpointer:對一些小物件使用,如nsnumber
·nonpointer_isa:非指標型的isa;應用於64位架構下的ios應用程式。在64位架構下,isa指標佔64個位元位,實際上有32位或者40位就夠用了,剩餘的位元位就浪費了。為了不讓記憶體浪費更好的管理記憶體,剩餘的32位蘋果用來儲存和記憶體管理相關的內容。
·雜湊表:是乙個複雜的資料結構,其中包含了引用計數表和弱引用表。
【詳解nonpointer_isa】
在64位架構下:
第一位has_assoc表示當前物件是否有關聯物件,0表示沒有,1表示有。
第二位has_cxx_dtor代表當前物件是否有c++**
第三位 3···31、32···35到第35位共33位,表示當前物件的類物件的記憶體位址。
第36···41位共6位,是magic 字段。
第42位weakly_referenced表示是否含有弱引用指標。
第43位deallocating表示當前指標是否正在進行dealloc操作。
第44位has_sidetable_rc表示當前isa指標的引用計數是否達到上限,如果達到上限需要外掛程式乙個sidetable,來額外儲存相關的引用計數內容。
第45···63位extra_rc表示額外的引用計數,儲存記憶體管理相關的,當引用計數很小的時候,就直接存在isa指標當中。
如下圖:
【詳解sidetable】
雜湊表是通過sidetables()結構來實現的,sidetables下面掛了很多sidetable,在不同的架構下是有不同個數的,比如說在非嵌入式系統中sidetable有64個。
sidetables()實際上是乙個雜湊表(hash),可以通過它的物件指標,找到它對應的引用計數表或者弱引用表具體在哪個sidetable中。
sidetable有自旋鎖(spinlock_t),引用計數表(refcountmap)和弱引用表(weak_table_t)。
sidetable結構:
自旋鎖:是忙等的鎖。如果鎖已經被其他執行緒獲取,那麼當前執行緒會自己去不斷的獲取是否被釋放,直到其他執行緒釋放。適用於輕量訪問。如+1,-1。
引用計數表:是hash表,其實就是hash查詢,插入和查詢通過同乙個hash函式,避免了迴圈遍歷,提高了查詢效率。
size_t實際上是乙個無符號long型(unsign long)的變數。在獲取物件的真實的引用計數值時,需要向右偏移兩位。
弱引用表:weak_table_t也是乙個hash表。
思考如下問題:
為什麼不是乙個sidetable?而是有多個sidetable組成乙個sidetables;或者說sidetables為什麼是多張表,而不是一張表?
解析:假設只有一張sidetable表,那麼記憶體中的所有物件的引用計數或者弱引用都儲存在這張表中,這個時候,如果我們要對某乙個物件的引用計數值進行操作,+1或者-1;由於不同的物件在不同的執行緒中,不同的執行緒操作同一張表,就有資源訪問的問題,那麼我們要對這張大表進行加鎖操作來保證資料訪問的安全性。在這個過程中就會產生乙個效率問題,比如,成千上萬的物件進行引用計數操作,那麼需要加鎖排隊,就會有效率問題。比如,現在已經有乙個物件在操作這個大表,那麼下個物件就要等前物件操作結束,把鎖釋放之後,它才能操作這張表。系統為了解決這種效率問題,引入了分離鎖。分離鎖就是把乙個大表分成幾個小表,a、b分別在不同表中,同時進行操作的話,可以併發進行,這樣就提高了訪問效率。
思考如下問題:
怎樣實現快速分流?找到當前物件在哪張表中?【快速分流指給出乙個物件的指標,如何快速的定位到這個這個物件在哪張表中】
解析:sidetables本質是一張hash表。
什麼是hash表?有乙個指標物件key,通過hash函式的運算,得到乙個值value,找到對應的sidetable。
思考如下問題:
你是否使用過自旋鎖,自旋鎖和普通鎖有什麼區別?適用於哪些場景?
解析:自旋鎖是忙等的鎖,適用於輕量訪問。
思考如下問題:
引用計數表示通過什麼實現的?為什麼引用計數表要用hash表來實現呢?
解析:是通過hash表實現的。插入和查詢都通過同乙個hash函式,避免了迴圈遍歷,提高了查詢效率。
關於記憶體管理的討論全部基於objc-runtime-680版本講解。
《記憶體管理》 記憶體
1.c c 記憶體分布 我們先來看下面的一段 和相關問題 int globalvar 1 static int staticglobalvar 1 void test char char2 abcd char pchar3 abcd int ptr1 int malloc sizeof int 4 ...
記憶體管理 記憶體管理概述
儲存器的發展方向是高速 大容量和小體積,即儲存器嘗試更高讀寫速度,更大儲存容量,更小物理體積。在計算機中,常見的儲存器有 暫存器,快取,記憶體,硬碟,一般硬碟之類的輔助儲存器又稱外存。在平均讀寫速度上,有 暫存器 快取 記憶體 外存 在單位容量 上,有 外存 記憶體 快取 暫存器 cpu處理器只能直...
記憶體管理相關函式
記憶體分配及釋放相關函式 void calloc int num,int size 在記憶體中動態地分配 num 個長度為 size 的連續空間,並將每乙個位元組 共num size 個 都初始化為 0。void malloc int num 在堆區分配一塊指定大小的記憶體空間,用來存放資料。這塊記...