對iOS開發中記憶體管理的一點總結與理解
阿新 • • 發佈:2019-02-10
做iOS開發也已經有兩年的時間,覺得有必要沉下心去整理一些東西了,特別是一些基礎的東西,雖然現在有ARC這種東西,但是我一直也沒有去用過,個人覺得對記憶體操作的理解是衡量一個程式設計師成熟與否的一個標準。好了,閒話不說,下面進入正題。 眾所周知,ObjectiveC的記憶體管理引用的一種叫做“引用計數“ (Reference Count)的操作方式,簡單的理解就是系統為每一個創建出來的物件,(這裡要注意,只是物件,NSObject的子類,基本型別沒有‘引用計數’)記錄一個引用計數,初始化這個物件的時候會呼叫alloc方法,系統在alloc方法裡會將這個物件的引用計數+1;例如:UIView *myview = [UIView alloc] init]; 這裡建立的物件myview它現在的引用技術就是1。所有的物件可以呼叫[xxx reatin];來使自身的引用計數+1。也可以呼叫[xxx release];讓自身的引用計數-1.如果一個物件的引用計數為0,那麼這個物件立即(記住,是立即)會被系統回收掉。除了[xxx reatin];會將物件的引用計數+1之外還有很多方法會將物件的引用技術+1,舉兩個最常用的:[self.view addSubView:myView];這個方法會將myView的引用計數+1。 NSArray類裡的[array addObject:myView];也會將引用計數+1。下面我會用程式碼說明一下幾個比較容易出錯的地方。
UIView *v = [[UIView alloc] init]; //分配後引用計數為1
[self.view addSubview:v]; //這兒引用計數加1,為2
[v release]; //這兒引用計數為-1為1
最後系統在回收self.view的時候,會先回收其subView,所以self.view被回收時v的引用計數是0,v就會立即被回收。
(二)成員變數物件的引用計數說明
(三)如果v是類的屬性,並且是宣告的時候是assginv = [[UIView alloc] init]; [self.view addSubview:v]; [v release]; 如果在dealloc裡呼叫了[v release];那麼就多release了,會crash.
@property (nonatomic, assign) UIView *v; 這兒是assign, 然後分配記憶體的時候如果是這樣
self.v = [[UIView alloc] init];//計數為1
[self.view addSubview:self.v];//計數為2
[self.v release];//計數為1
這時不需要在dealloc裡[self.v release];因為assign宣告的物件引用計數不會自動+1.當self.view被回收時,self.v的引用計數就會變成0;V就會被系統回收掉。
(四)如果v是類的屬性,並且是宣告的時候是reatin的@property (nonatomic, retain) UIView *v; 或 @property (nonatomic, copy) UIView *v;宣告的屬性,那麼這樣分配記憶體
v = [[UIView alloc] init];
[self.view addSubview:v];
[v release];這樣與a是一樣情況,不需要在dealloc裡釋放。
但如果是
self.v = [[UIView alloc] init];
[self.view addSubview:self.v];
[self.v release];加了個self,那麼就要在dealloc裡[v release];因為如果屬性用reatin宣告的時候,用self.初始化的時候物件的引用技術會自動+1。self.v = [[UIView alloc] init];//這個時候引用計數為2
下面聊聊autorelease,autorelease是objectiveC語言的一個比較特殊的機制,也是理解ObjectiveC記憶體管理的關鍵,Autorelease實際上只是把對release的呼叫延遲了,對於每一個Autorelease,系統只是把該Object放入了當前的Autorelease pool中,當該pool被釋放時,該pool中的所有Object會被呼叫Release。對的,其實autorelease就是一個延遲釋放的機制,比較好的介紹autorelease的文章:http://developer.51cto.com/art/201007/212523.htm 這篇文章個人認為autorelease講解的比較詳細,也易於理解。推薦大家看看,這裡除了這篇文章之外我還要談談我對autorelease的一些理解。我理解的是,系統在執行每一個函式的時候,會自動開啟一個autoreleasePool(記住是每一個函式的執行都會開啟一個autoreleasePool,而不是每一個類開啟一個,這一點很關鍵),在這個函式當中建立的所有用autorelease宣告的物件都會放進這一個的池當中。當函式執行完的時候,這一個autorelasepool 會被drain 掉,那麼池中所有引用計數為0的(千萬記住是引用計數為0)物件,就會被系統回收掉。寫到這裡很多人就會程式猿就會質疑我這個說法了,比如我在某一個UIViewController類的viewDidLoad函式裡面寫了:UIView *myView = [[UIView alloc] init] autorelease];[self.view addsubView:myView]; 的時候,當viewDidLoad函式執行完,為什麼myView物件沒有被回收。這是因為:因為呼叫了[self.view addsubView:myView];所以這時myView的引用計數變成了2,當函式執行完,autorelease被drain掉的時候,自動釋放池內所有的物件都會呼叫release方法,這時所有的物件的引用計數-1,如果這時物件的引用計數為0那麼它會被系統回收,如果不為0,那麼他還回被保留,也就是說自動釋放池中的物件不會因為自動釋放池的銷燬而被銷燬,自動釋放池的物件只是被延遲釋放了,池中物件的釋放也得滿足引用計數的機制。 以上就是我對IOS記憶體管理的一些簡單的理解,不對之處歡迎大家指正,咱們互相提高。