iOS程序的内存布局

- 栈区(stack):
- 存放函数的参数值、局部变量的值等,
- 由编译器自动分配释放,通常在函数执行结束后就释放了,其操作方式类似数据结构中的栈。
- 栈内存分配运算内置于处理器的指令集,效率很高。
- 分配的内存容量有限,比如iOS中栈区的大小是512k。
- 堆区(heap)
- C 语言使用 malloc、calloc、realloc 函数分配的空间,需要使用 free 函数释放
- 由程序员分配释放,若程序员不释放,会出现内存泄漏
- 分配方式类似于链表。
- 堆区的大小由系统决定,包括:系统内存/磁盘交换空间
栈区的特点
- 栈区的地址是连续的
- 栈区地址按照分配的顺序,由大到小顺序排列
- 访问速度快、栈区的内存由系统管理、后进先出/先进后出
堆区的特点
堆区的大小由系统决定,包括:系统内存/磁盘交换空间
- 所有程序共享、存储大数据、程序员管理
- 堆区的地址是不连续的
速度没有栈区快
如果只有一个方法使用,将 静态变量 定义在方法内部
- 如果有多个方法使用,将 静态变量 定义在 .m 中
-
常量
在
数据段为常量分配空间- const 关键字保证其后修饰的常量的值不允许被修改
- 在程序被加载到内存时,就会为常量分配空间并且设置初始值
- 如果没有指定初始值,会使用 0 作为初始值
- 常量名应该尽量的长以避免出现重名
//在 .m 中定义常量并且设置初始值const NSInteger cNum = 99;//在 .h 中使用 extern 关键字声明常量在其他位置定义并且已经赋值,外部可以直接使用extern const NSInteger cNum;
验证
int a = 10;int b;int main(int argc, char * argv[]) {@autoreleasepool {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);return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));}}/*字符串常量str=0x10dfa0068已初始化的全局变量、静态变量&a =0x10dfa0db8&c =0x10dfa0dbc未初始化的全局变量、静态变量&d =0x10dfa0e80&b =0x10dfa0e84堆obj=0x608000012210栈&f =0x7ffee1c60fe0&e =0x7ffee1c60fe4*/
Tagged Pointer
- 从
64bit开始,iOS引入了Tagged Pointer技术,用于优化NSNumber、NSDate、NSString等小对象的存储 - 在没有使用Tagged Pointer之前, NSNumber等对象需要动态分配内存、维护引用计数等,NSNumber指针存储的是堆中NSNumber对象的地址值

- 使用Tagged Pointer之后,NSNumber指针里面存储的数据变成了:
Tag + Data,也就是将数据直接存储在了指针中 - 当指针不够存储数据时,才会使用动态分配内存的方式来存储数据
objc_msgSend能识别Tagged Pointer,比如NSNumber的intValue方法,直接从指针提取数据,节省了以前的调用开销判断是否为Tagged Pointer

如何判断一个指针是否为Tagged Pointer?iOS平台,最高有效位是1(第64bit)
- Mac平台,最低有效位是1
OC对象的内存管理
- 在iOS中,使用引用计数来管理OC对象的内存
- 一个新创建的OC对象引用计数默认是1,当引用计数减为0,OC对象就会销毁,释放其占用的内存空间
- 调用
retain会让OC对象的引用计数+1,调用release会让OC对象的引用计数-1 - 内存管理的经验总结
- 当调用
alloc、new、copy、mutableCopy方法返回了一个对象,在不需要这个对象时,要调用release或者autorelease来释放它 - 想拥有某个对象,就让它的引用计数
+1;不想再拥有某个对象,就让它的引用计数-1
- 当调用
- 可以通过以下私有函数来查看自动释放池的情况
extern void _objc_autoreleasePoolPrint(void);
copy和mutableCopy
- 可变对象的
copy和mutableCopy都是深拷贝 - 不可变对象的
copy是浅拷贝,mutableCopy是深拷贝 copy方法返回的都是不可变对象 | | copy | mutableCopy | | —- | —- | —- | | NSString | NSString
浅拷贝 | NSMutableString
深拷贝 | | NSMutableString | NSString
深拷贝 | NSMutableString
深拷贝 | | NSArray | NSArray
浅拷贝 | NSMutableArray
深拷贝 | | NSMutableArray | NSArray
深拷贝 | NSMutableArray
深拷贝 | | NSDictionary | NSDictionary
浅拷贝 | NSMutableDictionary
深拷贝 | | NSMutableDictionary | NSDictionary
深拷贝 | NSMutableDictionary
深拷贝 |
引用计数的存储
在64bit中,引用计数可以直接存储在优化过的isa指针中,也可能存储在SideTable类中 

