由编译器管理(分配释放),栈从高地址向低地址扩展,是一块连续的内存区域,遵循先进后出原则,由编译器自动分配释放,存放函数参数值、局部变量的值(函数中的基本数据类型),栈区的操作方式类似于数据结构中的栈(先进后出)。栈内存分配运算效率很高,但是分配的内存量有限,比如iOS中栈区的大小是2M。
由程序员管理(分配释放),堆从低地址向高地址扩展数据,采用链表形式管理内存段,就是通过new、malloc、realloc分配的内存块,根据引用计数来判断是否释放,分配方式类似于数据结构中的链表。在iOS开发中所说的“内存泄漏”说的就是堆区的内存。
由编译器管理(分配释放),程序结束后由系统释放。存放全局变量和静态变量。有两块区域组成全局区(静态区),一块是存放未初始化的全局变量和静态变量,另一块是初始化完成的全局变量和静态变量,这两块区域是相邻的。
由编译器管理(分配释放),在编译阶段完成分配,存放常量字符串。
存放函数体的二进制代码。
NSString* string = @"abcd";//常量string->栈
NSInteger index = 0; //index->栈
NSMutableString* mString = [[NSMutableString alloc] initWithString:@"abcd"];//mString->堆
Objective-C提供了两种种内存管理方式:Manual Reference Counting
(MRC,手动引用计数器),Automatic Reference Counting
(ARC,自动引用计数)。ARC作为苹果新提供的技术,苹果推荐开发者使用ARC技术来管理内存;
无论是手动管理内存,还是ARC机制,都是通过对 引用计数
来进行内存管理的。
MRC模式下,所有的对象都需要手动的添加retain、release代码来管理内存。使用MRC,需要遵守谁创建,谁回收的原则。当引用计数为0的时候,必须回收,引用计数不为0,不能回收,如果引用计数为0,但是没有回收,会造成内存泄露。如果引用计数为0,继续释放,会造成野指针。为了避免出现野指针,我们在释放的时候,会先让指针=nil。
ARC是IOS5推出的新功能,通过ARC,可以自动的管理内存。在ARC模式下,只要没有强指针(强引用)指向对象,对象就会被释放。在ARC模式下,不允许使用retain、release、retainCount等方法。并且,如果使用dealloc方法时,不允许调用[super dealloc]方法。
ARC模式下的property变量修饰词为strong、weak,相当于MRC模式下的retain、assign。strong :代替retain,缺省关键词,代表强引用。weak:代替assign,声明了一个可以自动设置nil的弱引用,但是比assign多一个功能,指针指向的地址被释放之后,指针本身也会自动被释放。
属性默认修饰符:atomic、readwrite、strong(引用类型)、assign(基本类型)
retain
类似,使用之后,引用计数+1。strong
类似,使用之后,引用计数+1。nil
,一般IBOutlet、block、delegate
里面经常会用weak
,可以有效的避免野指针,其引用计数不会增加。assign
和unsafe_unretained
的作用和weak
相似,区别是如果属性指向的对象被释放,指针不会被置为nil
,会出现野指针crash
。如果assign
指向的是基本数据类型如NSIntegar
,那么将有栈来管理,不会出现野指针,iOS中默认对基本类型的修饰符就是assign
。NSString/NSArray/NSDictionary
,防止外面赋值是mutable数据改变以后导致里面的数据也被改了。只有实现了NSCopying
协议的对象才可以拷贝,否则会crash
。RunLoop
里注册了两个 Observer,其回调都是 _wrapRunLoopWithAutoreleasePoolHandler()
。Entry
(即将进入Loop),其回调内会调用 _objc_autoreleasePoolPush()
创建自动释放池。其 order
是-2147483647,优先级最高,保证创建释放池发生在其他所有回调之前。BeforeWaiting
(准备进入休眠) 时调用_objc_autoreleasePoolPop()
和 _objc_autoreleasePoolPush()
释放旧的池并创建新池;Exit
(即将退出Loop) 时调用 _objc_autoreleasePoolPop()
来释放自动释放池。这个 Observer 的 order
是 2147483647,优先级最低,保证其释放池子发生在其他所有回调之后。autoreleasepool
底层的数据结构是一个autoreleasepage
的双向链表,每个page
的大小为4096字节,除了存储成员变量的大小,其他的位置都用来存储autorelease
对象的地址,next变量永远指向下一个可以存放autorelease
对象地址的地址空间page1
存储空间用完后,会创建一个新的page2
,新的page2
的parent
指针指向满了的page1
,page1
的child指针会指向page2
;autoreleasepool
,会调用push
,程序结束时,最后会调用pop,回收所有autorelease
对象的内存;runloop
的休眠状态,调用push/pop
方法,管理autorelease
对象;push
的时候,会往page
里面添加一个哨兵对象,这个哨兵对象作为下次pop
函数的入参,遇到哨兵对象,说明这次runloop
循环添加到page
的autorelease
对象release
完毕。