標籤:
1.所謂使用類的靜態方法建立對象,就是指使用類名調用一次它的靜態方法(非顯式調用alloc)便可以得到一個建立的對象,比如下面兩個例子:
NSString* str1 = [NSString stringWithString:@"hello world"];
NSMutableString* str2 = [NSMutableString stringWithString:@"hello world"];
2. 第一個例子是使用字串的字面常量"hello world"建立一個NSString對象,已知常量在編譯期分配,存放在程式的資料區(常量區),全域唯一且不可改變;因為NSString對象是不可變的,所以str1直接指向資料區的"hello world",而不會在記憶體中棄置站台;而str2是可變的字串對象,因此需要將常量“hello world”的內容拷貝到記憶體,這樣才支援對字串內容的修改。因此,str1的建立基本上不增加記憶體開銷,而str2的建立會增加記憶體開銷。
3.NSString的靜態方法stringWithString會建立一個對象,為了保證該對象能夠被正確釋放,在返回該對象之前,會調用對象的autorelease方法,將對象的釋放操作交給了外層的自動釋放池對象;而對應的經典的alloc+init方式建立的對象,不會調用autorelease.因為當你顯式使用alloc時,ARC會給你添加相應的release操作,所以這種方式建立的對象可以被正常釋放。
4.記憶體泄露的例子
while(YES){ NSMutableString* str = [NSMutableString stringWithString@"hello world"]; }
使用死迴圈是為了使泄露的結果更更顯,如果每次操作的資料很大,那效果更明顯。
5.泄露的原因
每次建立對象str,都會開闢一塊新記憶體存放資料"hello world";而釋放的方式是autorelease,然而在此迴圈中接觸不到外層的自動釋放池,因此所有建立的對象都沒有被及時釋放掉,因此記憶體佔用會越來越大,效果如同記憶體泄露。
6.解決方式
一:迴圈內使用自動釋放池,及時釋放掉對象(不推薦,增加自動釋放池對象建立和銷毀開銷)
while(YES){ @autorelease{ NSMutableString* str = [NSMutableString stringWithString@"hello world"]; }}
二:使用經典的alloc+init方式建立對象(推薦,效率高而無副作用)
while(YES){ NSMutableString* str = [[NSMutableString alloc]initWithString:@"hello world"]; }
三:如果可能,使用NSString代替NSMutableString(不推薦,勉強規避)
while(YES){ NSString* str = [NSString stringWithString@"hello world"]; }
Object-C使用類靜態方法建立對象時容易記憶體泄露