赞
踩
一、垃圾回收机制
与Java语言相同Objective-c 2.0之后,也提供了垃圾回收机制。OC是支持垃圾回收机制的(Garbage collection简称GC),macOS开发中是支持的。但是在iOS移动终端设备中,并不支持垃圾回收机制。因此,iPhone并不能对内存进行自动垃圾回收处理(autorelease),并且他与GC的机制是不一样的。
ARC是在IOS5之后推出的新技术,在Xcode4.2及之后的版本中由于引入了ARC(Automatic Reference Counting)机制,程序编译时Xcode可以自动给你的代码添加内存释放代码,如果编写手动释放代码Xcode会报错。因此需要注意垃圾回收机制并不是ARC,ARC也是需要管理内存的,只不过是隐式的管理内存,编译器会在适当的地方自动插入retain,release和autorelease.
知识拓展:在Java中,程序员不需要去关心内存动态分配和垃圾回收的问题,这一切都交给了JVM来处理。Java中标记垃圾的算法主要有两种, 引用计数法和可达性分析算法。
二、内存管理中的几个概念:
引用计算器:既retainCount,每个OC对象内部都有1个8字节空间用来存储retainCount,表示有多少”人”正在使用;
对象刚被创建时,默认计数值就为1,当计数值为0时,系统会自动调用dealloc方法将对象销毁
引用计数器的用法:给对象发送相应的技术操作来改变计数器的值
retain消息:使计数器+1
release消息:使计数器-1
retainCount消息:得到当前当前retainCount的值
三、OC内存管理开发中需要事项
其一野指针,其二内存泄漏。
1)野指针:即指针所指的对象已经被销毁,但后续还在使用该指针,此时指针指向了一个什么都不是的东西,我们称它为野指针,那么如何防止野指针的,一般处理的方式是对象进行release操作后,在赋值对象nil值。
2)内存泄漏:在操作对象是没有遵循内存配对原则,创建了对象了,却未对对象进行销毁,此时这个未被销毁的对象就是我们所谓的内存中泄漏的对象,这种行为也就是所谓的内存泄漏,内存泄漏不会影响对象的正常运行,但会影响程序的效率。
除此之外还有1)提前释放:如果没有使用空间直接free 。2)重复释放,如果你对一个空间进行了多次free 。
四、MRC(Manual Reference Counting)相关语法
1.关闭ARC
target -》 build setting - 》搜索 gar YES to NO
2.ARC和MRC混编
[工程]—>[Build Phases]—>[Compile Sources]—>
双击不想参与ARC的文件-fno-objc-arc
3.MRC管理黄金法则
1.凡是使用alloc,retain ,new ,copy(开头),mutableCopy(开头)的方法,都必须使用release 或者 autorelease 方法来【释放】
2.谁写alloc 谁负责release 那个类alloc 那个类release
4.一个简单的例子说明MRC
这里有一个Person类
这里是打印结果
我们在看看下面这一个例子
当执行release操作时,一个对象的引用计数为0时,它就会被释放掉。
什么是autorelease?
autorelease类似于C语言中Automatic variable自动变量,程序执行时,若某自动变量超出其作用域,该自动变量将被自动废弃。
autorelease何时释放?
在没有使用@autoreleasepool的情况,autorelease对象是在当前的runloop迭代结束时释放。每个runloop中都会创建一个autoreleasepool并在runloop迭代结束进行释放。如果是手动创建autoreleasepool,自己创建Pool并释放。
// MRC NSAutoreleasePool *pool = [NSAutoreleasePool alloc] init]; id obj = [NSObject alloc] init]; [obj autorelease]; [pool drain]; // ARC @autoreleasepool { id obj = [NSObject alloc] init]; }
可以发现:整个 iOS 的应用都是包含在一个自动释放池 block 中的
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
@autoreleasepool{} 本质上是一个结构体:
struct __AtAutoreleasePool {
__AtAutoreleasePool() {atautoreleasepoolobj = objc_autoreleasePoolPush();}
~__AtAutoreleasePool() {objc_autoreleasePoolPop(atautoreleasepoolobj);}
void * atautoreleasepoolobj;
};
这个结构体在初始化的时候会调用:objc_autoreleasePoolPush() 方法
在析构的时候,会调用:objc_autoreleasePoolPop 方法
这表明,main函数实际工作的时候,是这样的:
int main(int argc, const char * argv[]) {
{
void * atautoreleasepoolobj = objc_autoreleasePoolPush();
// do things you want
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
objc_autoreleasePoolPop(atautoreleasepoolobj);
}
return 0;
}
那么 objc_autoreleasePoolPush 和 objc_autoreleasePoolPop又是什么呢?
void *objc_autoreleasePoolPush(void) {
return AutoreleasePoolPage::push();
}
void objc_autoreleasePoolPop(void *ctxt) {
AutoreleasePoolPage::pop(ctxt);
}
上面的方法看上去是对 AutoreleasePoolPage 对应静态方法 push 和 pop 的封装。
class AutoreleasePoolPage {
magic_t const magic; //AutoreleasePoolPage 完整性校验
id *next;
pthread_t const thread; //所在线程
AutoreleasePoolPage * const parent;
AutoreleasePoolPage *child;
uint32_t const depth;
uint32_t hiwat;
};
每一个自动释放池都是由一系列的 AutoreleasePoolPage 组成的,并且每一个 AutoreleasePoolPage 的大小都是 4096 字节(16 进制 0x1000)
自动释放池就是由 AutoreleasePoolPage 构成的双向链表。
POOL_SENTINEL(哨兵对象)
在每个自动释放池初始化调用 objc_autoreleasePoolPush 的时候,都会把一个 POOL_SENTINEL push 到自动释放池的栈顶,并且返回这个 POOL_SENTINEL 哨兵对象。
int main(int argc, const char * argv[]) {
{
//这里的 atautoreleasepoolobj 就是一个 POOL_SENTINEL
void * atautoreleasepoolobj = objc_autoreleasePoolPush();
// do whatever you want
objc_autoreleasePoolPop(atautoreleasepoolobj);
}
return 0;
}
上面的 atautoreleasepoolobj 就是一个 POOL_SENTINEL。
而当方法 objc_autoreleasePoolPop 调用时,就会向自动释放池中的对象发送 release 消息,直到第一个 POOL_SENTINEL。
注:下篇文章博主会详细讲解各种属性修饰符,请持续关注;
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。