標籤:des style blog http color ar 使用 for sp
此日誌用於記錄下學習過程中碰到的問題
《Objective-C進階編程》 人民郵電出版社 是一本寫的很棒的書,日本作者對於細節摳的很仔細,深入淺出,推薦學習Objective-C的同學們購買。
#1 關於retainCount 變數在記憶體中是如何存放的?
在GNUStep(一種cocoa架構的互換架構)中retainCount和對象放置在一起,在對象地址之前。所以有如下擷取GNUstep中retainCount的方式:
-(NSUInteger) retainCount{ return NSExtraRefCount(self) + 1;}inline NSUIntegerNSExtraRefCount(id anObject){ return ((struct obj_layout *) anObject )[-1].retained;}
不過蘋果的實現是管理了一張hashTable,在通過hash(obj),在相應的位置加入該對象的引用技術retainCount和對象記憶體塊的地址。
雖然GNUstep的實現方式可能會更加直觀一些,不過蘋果這麼做也是有相應的好處的:
- 對象的記憶體塊分配無需考慮記憶體塊的頭部。
- 引用計數表中各記錄中存有記憶體塊地址,可從各個記錄追溯到各個對象的記憶體塊。在調試過程中很重要。另外在利用工具監測記憶體流失時,引用計數表中的各記錄也有助於監測各對象的持有人是否存在。
#2 autorelease & NSRunloop ?
NSAutoreleasePool這個類對於pool對象使用了管理者模式,即會管理許多個pool 並且記錄當前正在使用的pool,如果在別的地方使用了 [[[class alloc] init] autorelease],那麼該對象就會被加入這個正在使用的pool中。
- [pool drain] 方法會廢棄該pool 並且對pool中的所有對象進行一次release;
- 新定義的pool總是當前正在使用的pool,所以在多個NSAutoreleasePool嵌套使用時,加入的總是最內層的pool;
- NSRunloop象徵著程式的主迴圈,每次NSRunloop開始的時候都會定義一個autoreleasepool,當Runloop結束的時候會調用該pool的drain方法。具體的NSRunloop在後續章節中會有介紹。
#3 如何提高Objective-C方法的調用速度?
“IMP Caching”方法
提高頻繁調用的autorelease方法的速度:例
id autorelease_class = [NSAutoreleasePool class];SEL autorelease_sel = @selector(addObject:);IMP autorelease_imp = [autorelease_class methodForSelector:autorelease_sel];- (id) autorelease{ (* autorelease_imp)(autorelease_class,autorelease_sel,self);}- (id)autorelease{ [NSAutoreleasePool addObject:self];}
在架構初始化的時候對,這幾個方法進行了緩衝。第一種autorelease的調用速度是後者的2倍。因為Oc-runtime 中有對象之間發送訊息的開銷。
#4 SEL 和 IMP的區別?
typedef struct objc_selector *SEL;
typedef id (*IMP)(id, SEL, ...);
IMP 是一個函數指標,這個被指向的函數包含一個接收訊息的對象id(self 指標), 調用方法的選標 SEL (方法名),以及不定個數的方法參數,並返回一個id。也就是說 IMP 是訊息最終調用的執行代碼,是方法真正的實現代碼 。我們可以像在C語言裡面一樣使用這個函數指標。
#5 _weak 賦值給 _strong 時的情況?
- 如果_strong 變數為nil , _weak對象所指的對象的引用計數器加1;
- 如果_strong 變數為某個對象那麼,會hash(obj) 調用內部的release,然後將_weak所指的對象的引用計數器加1;
- 如果_strong 變數和_weak所指的都是一個對象,那麼不做任何操作。(如果是release之後retain ?那麼絕對會出現問題,如果剛好_strong所指的對象的retainCount為1,待驗證)
- 如果_weak 所指為nil , 那麼等同於 obj = nil; 對於原先指向對象的retainCount –1 ;
#6 _unsafe_unretained 為何物?
實際上就是不會自動置nil的指標 (_weak),所以可能會出現野指標。
#7 @autorelease 塊
在塊結束的時候調用,[pool drain] ;
#8 C++智能指標的問題 std:: shared_ptr & std:: weak_ptr & std:: auto_ptr
引入了引用計數器的概念。
#9 NSZone是什嗎?
在碰到allocWithZone, copyWithZone總會有個疑問,這個NSZone到底是個什麼東西?簡單來說,可以想象成一個記憶體池,alloc或是dealloc這些操作,都是在這個記憶體池中操作的。cocoa總是會配置一個預設的NSZone,任何預設的記憶體操作都是在這個“zone”上操作的。預設的NSZone的缺陷在於,它是全域範圍的,時間一長,必然會導致記憶體的片段化,如果你需要大量的alloc一些object,那麼效能就會受到一些影響。所有cocoa提供方法,你可以自己產生一個NSZone,並將alloc, copy全部限制在這個“zone”之內。
#10 在刪除動態數組的時候需要注意的?
需要講所有元素置為nil,不然會發生記憶體流失。即使使用memset等函數將記憶體填充為0也不會釋放所賦值的對象。對於編譯器,必須明確得使用賦值給附有_strong 修飾的變數的原始碼。
for( NSUInteger i = 0; i < entries ;++i ) array[i] = nil ;free(array);
#11 _weak表
在ARC條件下,當_weak指向的對象被釋放了,那麼_weak會自動被置為nil,那麼runtime中是如何做到這一點的呢?
在記憶體中維護一張weak表。
/* oc代碼 */{ id __weak obj1 = obj;}/* 編譯器類比代碼 */id obj1;objc_initWeak(&obj1,obj);objc_destroyWeak(&obj1);
如上述代碼,key 為對象的地址 obj ,values為 _weak的地址&obj1 。 一個對象地址可以對應很多個_weak變數地址,當一個對象被析構,那麼他在weak表中所指向的_weak變數就會被置為nil。然後在weak表中刪除該記錄。
由於使用_weak變數會造成以上的系統開銷,所以僅在需要避免循環參考的時候使用__weak修飾符。
#12 在ARC條件下如何擷取retainCount ?
使用: _objc_rootRetainCount(obj);
《Objective-C進階編程》の記憶體管理の學習筆記