一 iOS程序的內(nèi)存布局

代碼段:編譯之后的代碼
-
數(shù)據(jù)段
- 字符串常量:比如NSString *str = @"123"
- 已初始化數(shù)據(jù):已初始化的全局變量、靜態(tài)變量等
- 未初始化數(shù)據(jù):未初始化的全局變量、靜態(tài)變量等
棧:函數(shù)調(diào)用開(kāi)銷(xiāo),比如局部變量。分配的內(nèi)存空間地址越來(lái)越小
堆:通過(guò)alloc、malloc、calloc等動(dòng)態(tài)分配的空間,分配的內(nèi)存空間地址越來(lái)越大
代碼例子如下
int a = 10;
int b;
implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self test1];
}
- (void)test1 {
static int c = 20;
static int d;
int e;
int f = 20;
NSString *str = @"123";
NSObject *obj = [[NSObject alloc] init];
NSLog(@"\n&a=%p\n&b=%p\n&c=%p\n&d=%p\n&e=%p\n&f=%p\nstr=%p\nobj=%p\n",
&a, &b, &c, &d, &e, &f, str, obj);
}
分析結(jié)果如下
/*
字符串常量
str=0x1029a4068
已初始化的全局變量、靜態(tài)變量
&a =0x1029a4db8
&c =0x1029a4dbc
未初始化的全局變量、靜態(tài)變量
&d =0x1029a4e80
&b =0x1029a4e84
堆
obj=0x60400001b510
棧
&f =0x7ffeed25a990
&e =0x7ffeed25a994
*/
二 Tagged Pointer
從64bit開(kāi)始,iOS引入了
Tagged Pointer技術(shù),用于優(yōu)化NSNumber、NSDate、NSString等小對(duì)象的存儲(chǔ)在沒(méi)有使用
Tagged Pointer之前, NSNumber等對(duì)象需要?jiǎng)討B(tài)分配內(nèi)存、維護(hù)引用計(jì)數(shù)等,NSNumber指針存儲(chǔ)的是堆中NSNumber對(duì)象的地址值使用
Tagged Pointer之后,NSNumber指針里面存儲(chǔ)的數(shù)據(jù)變成了:Tag + Data,也就是將數(shù)據(jù)直接存儲(chǔ)在了指針中當(dāng)指針不夠存儲(chǔ)數(shù)據(jù)時(shí),才會(huì)使用動(dòng)態(tài)分配內(nèi)存的方式來(lái)存儲(chǔ)數(shù)據(jù)
objc_msgSend能識(shí)別Tagged Pointer,比如NSNumber的intValue方法,直接從指針提取數(shù)據(jù),節(jié)省了以前的調(diào)用開(kāi)銷(xiāo)-
如何判斷一個(gè)指針是否為
Tagged Pointer?-
iOS平臺(tái),最高有效位是1(第64bit) -
Mac平臺(tái),最低有效位是1
-
三 判斷是否為T(mén)agged Pointer
// 如果是iOS平臺(tái)(指針的最高有效位是1,就是Tagged Pointer)
# define _OBJC_TAG_MASK (1UL<<63)
// 如果是Mac平臺(tái)(指針的最低有效位是1,就是Tagged Pointer)
# define _OBJC_TAG_MASK 1UL
- (BOOL)isTaggedPointer:(id)pointer {
return ((uintptr_t)pointer & _OBJC_TAG_MASK) == _OBJC_TAG_MASK;
}
調(diào)用
// 是否是tagger pointer
- (void)test3 {
NSNumber *number1 = @4;
NSNumber *number2 = @5;
NSNumber *number3 = @(0xFFFFFFFFFFFFFFF);
NSLog(@"%d %d %d", [self isTaggedPointer:number1], [self isTaggedPointer:number2], [self isTaggedPointer:number3]);
NSLog(@"%p %p %p", number1, number2, number3);
}
執(zhí)行結(jié)果

圖解說(shuō)明

四 MRC
1.MRC環(huán)境下Set方法內(nèi)部實(shí)現(xiàn)
- 被
assign修飾
@property (nonatomic, assign) int age;
- (void)setAge:(int)age {
_age = age;
}
- (int)age {
return _age;
}
- 被
retain修飾
@property (nonatomic, retain) Dog *dog;
- (void)setDog:(Dog *)dog {
if (_dog != dog) {
[_dog release];
_dog = [dog retain];
}
}
- (Dog *)dog {
return _dog;
}
- 被
copy修飾
@property (copy, nonatomic) NSArray *data;
- (void)setData:(NSArray *)data {
if (_data != data) {
[_data release];
_data = [data copy];
}
}
五 OC對(duì)象的內(nèi)存管理
在iOS中,使用引用計(jì)數(shù)來(lái)管理OC對(duì)象的內(nèi)存
一個(gè)新創(chuàng)建的OC對(duì)象引用計(jì)數(shù)默認(rèn)是1,當(dāng)引用計(jì)數(shù)減為0,OC對(duì)象就會(huì)銷(xiāo)毀,釋放其占用的內(nèi)存空間
調(diào)用retain會(huì)讓OC對(duì)象的引用計(jì)數(shù)+1,調(diào)用release會(huì)讓OC對(duì)象的引用計(jì)數(shù)-1
內(nèi)存管理的經(jīng)驗(yàn)總結(jié)
當(dāng)調(diào)用alloc、new、copy、mutableCopy方法返回了一個(gè)對(duì)象,在不需要這個(gè)對(duì)象時(shí),要調(diào)用release或者autorelease來(lái)釋放它
想擁有某個(gè)對(duì)象,就讓它的引用計(jì)數(shù)+1;不想再擁有某個(gè)對(duì)象,就讓它的引用計(jì)數(shù)-1
可以通過(guò)以下私有函數(shù)來(lái)查看自動(dòng)釋放池的情況
pextern void _objc_autoreleasePoolPrint(void);
// 聲明一
NSMutableArray *data = [[NSMutableArray alloc] init];
self.data = data;
[data release];
// 聲明二
NSMutableArray *data = [NSMutableArray array];
self.data = data;
兩個(gè)聲明方式相同,只是一個(gè)有調(diào)用
release操作,一個(gè)沒(méi)有。因?yàn)?code>array內(nèi)部會(huì)調(diào)用autorelease方法。
本文參考:
路飛_Luck (http://www.itdecent.cn/p/07f7b96bb03f)
以及借鑒MJ的教程視頻
非常感謝.
項(xiàng)目連接地址 - MemoryManage-CADisplayLink+Timer