废话不多说,赞么直奔主题.
1.0 苹果的实现
NSObject内存申请过程
+alloc
+allocWithZone
class_createInstance
calloc //分配内存块
1.1 autorelease
对象当超出其作用域时,对象实例的release实例方法被调用。
使用方法:
1、生成并持有NSAutoreleasePool对象
2、调用已分配对象的autorelease实例方法
3、废弃NSAutoreleasePool对象
对于所有在autoreleasePool对象的作用域中的对象,在废弃autoreleasePoll对象时,所有调用autorelease的实例对象都会调用release方法。
在Cocoa框架中,相当于程序住循环的NSRunLoop或者在其他程序可运行的地方,对NSAutoreleasePool对象进行生成、持有和废弃处理。
当在一个循环中产生大量的autorelease对象,内存占用很大的时候,可以使用autoreleasePool对象。
1.1.1 autorelease实现
[obj autorelease]; 本质就是调用 [NSAutoreleasePoll addObject:self];
苹果实现
源码是在runtime/NSObject.mm文件夹下,autoreleasePool内部是使用链表实现的,每个节点是autoreleasePoolPage,使用POOL_BOUNDARY作为每个节点中保存数据的边界,当数组中满的时候后,会新生成一个autoreleasePoolPage节点,使当前节点的child指向新创建的page,看下autoreleasePoolPage结构:
class AutoreleasePoolPage
{
# define EMPTY_POOL_PLACEHOLDER ((id*)1)
# define POOL_BOUNDARY nil //边界
static pthread_key_t const key = AUTORELEASE_POOL_KEY;
static uint8_t const SCRIBBLE = 0xA3; // 0xA3A3A3A3 after releasing
static size_t const SIZE =
#if PROTECT_AUTORELEASEPOOL
PAGE_MAX_SIZE; // must be multiple of vm page size
#else
PAGE_MAX_SIZE; // size and alignment, power of 2
#endif
static size_t const COUNT = SIZE / sizeof(id);//保存数据大小
magic_t const magic; //验证当前poll结构是否完整
id *next;
pthread_t const thread; //当前所在线程
AutoreleasePoolPage * const parent; //父节点
AutoreleasePoolPage *child; //子节点
uint32_t const depth;
uint32_t hiwat;
}
主要方法
//新建autoreleasePoolPage
AutoreleasePoolPage(AutoreleasePoolPage *newParent)
: magic(), next(begin()), thread(pthread_self()),
parent(newParent), child(nil),
depth(parent ? 1+parent->depth : 0),
hiwat(parent ? parent->hiwat : 0)
{
if (parent) {
parent->check();
assert(!parent->child);
parent->unprotect();
parent->child = this;
parent->protect();
}
protect();
}
//添加对象
id *add(id obj)
{
assert(!full());
unprotect();
id *ret = next; // faster than `return next-1` because of aliasing
*next++ = obj;
protect();
return ret;
}
//释放所有对象
void releaseAll()
{
releaseUntil(begin());
}
void releaseUntil(id *stop) { }
//获取当前正在使用的page
static inline AutoreleasePoolPage *hotPage()
{
AutoreleasePoolPage *result = (AutoreleasePoolPage *)
tls_get_direct(key);
if ((id *)result == EMPTY_POOL_PLACEHOLDER) return nil;
if (result) result->fastcheck();
return result;
}
//设置当前page
static inline void setHotPage(AutoreleasePoolPage *page)
{
if (page) page->fastcheck();
tls_set_direct(key, (void *)page);
}
static inline id *autoreleaseFast(id obj)
{
AutoreleasePoolPage *page = hotPage();
if (page && !page->full()) {
return page->add(obj);
} else if (page) {
return autoreleaseFullPage(obj, page);
} else {
return autoreleaseNoPage(obj);
}
}
public: static inline id autorelease(id obj)
{
assert(obj);
assert(!obj->isTaggedPointer());
id *dest __unused = autoreleaseFast(obj);
assert(!dest || dest == EMPTY_POOL_PLACEHOLDER || *dest == obj);
return obj;
}
//往当前page中添加新对象
static inline void *push()
{
id *dest;
if (DebugPoolAllocation) {
// Each autorelease pool starts on a new pool page.
dest = autoreleaseNewPage(POOL_BOUNDARY);
} else {
dest = autoreleaseFast(POOL_BOUNDARY);
}
assert(dest == EMPTY_POOL_PLACEHOLDER || *dest == POOL_BOUNDARY);
return dest;
}
//pop对象,销毁
static inline void pop(void *token)
{ }
```c s NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
//等同于 objc_autoreleasePoolPush();
Person *p = [[Person alloc] init];
[p autorelease];// 等同于 objc_autorelease(p);
p.name = @””;
[pool drain];//相当于release
//等同于 objc_autoreleasePoolPop(pool); ```
对pool不能进行autorelease操作,否则发生异常,autoreleasePool重载了autorelease方法,会运行时就出错。