接上文?http://www.lxweimin.com/p/a9cc0806c3f5
本文繼續探討NSMutableArray與NSMutableSet的內存結構。
NSMutableArray
依然是使用位移指針查看內容的方式探索
代碼跟NSArray大差不差。可以看出:
第一個內存單元與NSArray相同,前28位為定值應該是類內恒定的值,后36位為isa指針+1。
第二個內存單元恒為空。
重點研究第三個內存單元及以后。
根據二次尋址可得,第三個內存單元指向的正是array[0]所存儲數據的地址,且目標地址向后依次順序存儲了array的其他元素,推測此表為順序表,存儲內容為array中包含的元素,而第三個內存單元指向其首地址。
第四個內存單元,前四個字節存儲一個偶數,其值為不小于count的最小偶數,推測是其為存儲順序表開辟的內存空間。后四個字節為空。
第五個內存單元,前四個字節存儲count,后四個字節恒為1。暫時不了解后四個字節代表的意義。
第六個內存單元就是空了,這里不再對第六個及以后的內存單元進行探究。
可變數組的增刪
因為改查對數據內存結構基本沒有影響,所以此方法不討論改和查
以下可能圖比較多,想看結論建議直接跳過。
第二次打印的時候,容量未溢出,僅僅在順序表后添加了新元素,第五個內存單元,前四個字節代表的count發生相應改變,后四個字節+1,后四個字節在之后的操作中單向增加,添加+1,刪除+2,筆者暫時推測這是個代表操作次數的值。
第三次打印的時候,容量溢出,筆者發現array直接放棄了原先的順序表開辟了新的內存創建順序表。且讀取上一個順序表發現數據已不存在。容量也不再是按照不小于count的最小偶數,而是比之增加了2。
第四次打印的時候,容量未改變,只是count發生了改變,特別的,刪除索引的后續索引數據向前填充,但超出容量的數據并未清零,推測array用count識別數量,溢出部分不會影響邏輯。
繼續探尋當插入數據與刪除數據位于前半段時,對應內存結構的變化。
上代碼:
第二次打印的時候,容量未溢出,替換元素來到了原先array[0]的位置,array[0]的元素來到了array[6]的內存位置,同時第四個存儲單元的后四個字節變為5,推測其值為首個元素的游標,由此可知,array是環形存儲的,插入元素時在內存內優先移動元素少的一邊,同時游標會移動指出順序表的首位元素。
第三次打印的時候,容量溢出,同樣開辟新內存構建新順序表,新元素占據第一個位置,因為這里牽扯到內存重新開辟,所以不需要前移新元素。array[0]依舊位于內存最后位置,由此驗證游標推論屬實。
第四第五次打印的時候,內存不變,同樣是短端移動,廢棄內存不重置。用游標和count來控制數組索引。
由此可得結論,NSMutableArray結構為:
第一個內存單元與NSArray相同,前28位為定值應該是類內恒定的值,后36位為isa指針+1。
第二個內存單元恒為空。
第三個內存單元存儲一個指向順序表的地址,此順序表存放可變數組元素。
第四個內存單元,前四個字節存儲順序表的內存空間,后四個字節存儲索引游標,游標數代表第一個元素在順序表的位置。
第五個內存單元,前四個字節存儲數組的count,后四個字節存儲一個跟操作有關的單調增長的值,每次操作數組都會增加。
超出存儲長度時,array會放棄原順序表,申請更多的內存構建新的順序表。
這里繼續說一下MutableSet,因為測試方法雷同,所以不再貼代碼。
可得結論,MutableSet結構為:
第一個內存單元與NSSet相同,前28位為定值應該是類內恒定的值,后36位為isa指針+1。
第二個內存單元恒為空。
第三個內存單元存儲一個指向順序表的地址,此順序表存放可變集合元素。
第四個內存單元,前四個字節存儲集合的count,后四個字節存儲一個跟操作有關的單調增長的值,每次操作集合都會增加。
超出存儲長度時,set會放棄原順序表,申請更多的內存構建新的順序表。
這里說下可變set與array的不同,set沒有順序不需要游標,只用count控制,遇到空元素跳過就好了。添加與刪除set元素不會移動其他元素,刪除會用一個空的object填補此處,set在使用的時候會將其理解為空。筆者通過po方法只能得出此元素為NSObject的結論,并不能繼續分析之。