《Objective-C高級編程》の內存管理の學習筆記

此日誌用於記錄下學習過程當中碰到的問題 忍者

轉載請註明出處: http://www.cnblogs.com/xdxer/p/4069650.htmlhtml

《Objective-C高級編程》 人民郵電出版社  是一本寫的很棒的書,日本做者對於細節摳的很仔細,深刻淺出,推薦學習Objective-C的同窗們購買。編程

 

#1 關於retainCount 變量在內存中是如何存放的?數組

在GNUStep(一種cocoa框架的互換框架)中retainCount和對象放置在一塊兒,在對象地址以前。因此有以下獲取GNUstep中retainCount的方式:緩存

-(NSUInteger) retainCount
{
    return NSExtraRefCount(self) + 1;
}

inline NSUInteger
NSExtraRefCount(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中。oop

  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);

相關文章
相關標籤/搜索