《Objective-C進階編程》の記憶體管理の學習筆記

來源:互聯網
上載者:User

標籤: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的實現方式可能會更加直觀一些,不過蘋果這麼做也是有相應的好處的:

  1. 對象的記憶體塊分配無需考慮記憶體塊的頭部。
  2. 引用計數表中各記錄中存有記憶體塊地址,可從各個記錄追溯到各個對象的記憶體塊。在調試過程中很重要。另外在利用工具監測記憶體流失時,引用計數表中的各記錄也有助於監測各對象的持有人是否存在。

#2   autorelease & NSRunloop ?

NSAutoreleasePool這個類對於pool對象使用了管理者模式,即會管理許多個pool 並且記錄當前正在使用的pool,如果在別的地方使用了 [[[class alloc] init] autorelease],那麼該對象就會被加入這個正在使用的pool中。

  1. [pool drain] 方法會廢棄該pool 並且對pool中的所有對象進行一次release;
  2. 新定義的pool總是當前正在使用的pool,所以在多個NSAutoreleasePool嵌套使用時,加入的總是最內層的pool;
  3. 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 時的情況?

  1. 如果_strong 變數為nil , _weak對象所指的對象的引用計數器加1;
  2. 如果_strong 變數為某個對象那麼,會hash(obj) 調用內部的release,然後將_weak所指的對象的引用計數器加1;
  3. 如果_strong 變數和_weak所指的都是一個對象,那麼不做任何操作。(如果是release之後retain ?那麼絕對會出現問題,如果剛好_strong所指的對象的retainCount為1,待驗證)
  4. 如果_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進階編程》の記憶體管理の學習筆記

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.