Objective-C autorelease

// main.m
int main(int argc, char * argv[]) {
@autoreleasepool { }
}

  

clang -rewrite-objc main.m
__AtAutoreleasePool __autoreleasepool; 
struct __AtAutoreleasePool {
__AtAutoreleasePool() {atautoreleasepoolobj = objc_autoreleasePoolPush();}
~__AtAutoreleasePool() {objc_autoreleasePoolPop(atautoreleasepoolobj);}
void * atautoreleasepoolobj;
};
class AutoreleasePoolPage
{ #define POOL_SENTINEL 0
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
4096; // must be multiple of vm page size
#else
4096; // size and alignment, power of 2
#endif
static size_t const COUNT = SIZE / sizeof(id); magic_t const magic;
id *next;
pthread_t const thread;
AutoreleasePoolPage * const parent;
AutoreleasePoolPage *child;
uint32_t const depth;
uint32_t hiwat; // SIZE-sizeof(*this) bytes of contents follow static void * operator new(size_t size) {
return malloc_zone_memalign(malloc_default_zone(), SIZE, SIZE);
}
static void operator delete(void * p) {
return free(p);
} inline void protect() {
#if PROTECT_AUTORELEASEPOOL
mprotect(this, SIZE, PROT_READ);
check();
#endif
} inline void unprotect() {
#if PROTECT_AUTORELEASEPOOL
check();
mprotect(this, SIZE, PROT_READ | PROT_WRITE);
#endif
} AutoreleasePoolPage(AutoreleasePoolPage *newParent)
: magic(), next(begin()), thread(pthread_self()),
parent(newParent), child(NULL),
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();
} ~AutoreleasePoolPage()
{
check();
unprotect();
assert(empty()); // Not recursive: we don't want to blow out the stack
// if a thread accumulates a stupendous amount of garbage
assert(!child);
} void busted(bool die = true)
{
(die ? _objc_fatal : _objc_inform)
("autorelease pool page %p corrupted\n"
" magic 0x%08x 0x%08x 0x%08x 0x%08x\n pthread %p\n",
this, magic.m[0], magic.m[1], magic.m[2], magic.m[3],
this->thread);
} void check(bool die = true)
{
if (!magic.check() || !pthread_equal(thread, pthread_self())) {
busted(die);
}
} void fastcheck(bool die = true)
{
if (! magic.fastcheck()) {
busted(die);
}
} id * begin() {
return (id *) ((uint8_t *)this+sizeof(*this));
} id * end() {
return (id *) ((uint8_t *)this+SIZE);
} bool empty() {
return next == begin();
} bool full() {
return next == end();
} bool lessThanHalfFull() {
return (next - begin() < (end() - begin()) / 2);
} id *add(id obj)
{
assert(!full());
unprotect();
*next++ = obj;
protect();
return next-1;
} void releaseAll()
{
releaseUntil(begin());
} void releaseUntil(id *stop)
{
// Not recursive: we don't want to blow out the stack
// if a thread accumulates a stupendous amount of garbage while (this->next != stop) {
// Restart from hotPage() every time, in case -release
// autoreleased more objects
AutoreleasePoolPage *page = hotPage(); // fixme I think this `while` can be `if`, but I can't prove it
while (page->empty()) {
page = page->parent;
setHotPage(page);
} page->unprotect();
id obj = *--page->next;
memset((void*)page->next, SCRIBBLE, sizeof(*page->next));
page->protect(); if (obj != POOL_SENTINEL) {
objc_release(obj);
}
} setHotPage(this); #ifndef NDEBUG
// we expect any children to be completely empty
for (AutoreleasePoolPage *page = child; page; page = page->child) {
assert(page->empty());
}
#endif
} void kill()
{
// Not recursive: we don't want to blow out the stack
// if a thread accumulates a stupendous amount of garbage
AutoreleasePoolPage *page = this;
while (page->child) page = page->child; AutoreleasePoolPage *deathptr;
do {
deathptr = page;
page = page->parent;
if (page) {
page->unprotect();
page->child = NULL;
page->protect();
}
delete deathptr;
} while (deathptr != this);
} static void tls_dealloc(void *p)
{
// reinstate TLS value while we work
setHotPage((AutoreleasePoolPage *)p);
pop(0);
setHotPage(NULL);
} static AutoreleasePoolPage *pageForPointer(const void *p)
{
return pageForPointer((uintptr_t)p);
} static AutoreleasePoolPage *pageForPointer(uintptr_t p)
{
AutoreleasePoolPage *result;
uintptr_t offset = p % SIZE; assert(offset >= sizeof(AutoreleasePoolPage)); result = (AutoreleasePoolPage *)(p - offset);
result->fastcheck(); return result;
} static inline AutoreleasePoolPage *hotPage()
{
AutoreleasePoolPage *result = (AutoreleasePoolPage *)
tls_get_direct(key);
if (result) result->fastcheck();
return result;
} static inline void setHotPage(AutoreleasePoolPage *page)
{
if (page) page->fastcheck();
tls_set_direct(key, (void *)page);
} static inline AutoreleasePoolPage *coldPage()
{
AutoreleasePoolPage *result = hotPage();
if (result) {
while (result->parent) {
result = result->parent;
result->fastcheck();
}
}
return result;
} static inline id *autoreleaseFast(id obj)
{
AutoreleasePoolPage *page = hotPage();
if (page && !page->full()) {
return page->add(obj);
} else {
return autoreleaseSlow(obj);
}
} static __attribute__((noinline))
id *autoreleaseSlow(id obj)
{
AutoreleasePoolPage *page;
page = hotPage(); // The code below assumes some cases are handled by autoreleaseFast()
assert(!page || page->full()); if (!page) {
assert(obj != POOL_SENTINEL);
_objc_inform("Object %p of class %s autoreleased "
"with no pool in place - just leaking - "
"break on objc_autoreleaseNoPool() to debug",
obj, object_getClassName(obj));
objc_autoreleaseNoPool(obj);
return NULL;
} do {
if (page->child) page = page->child;
else page = new AutoreleasePoolPage(page);
} while (page->full()); setHotPage(page);
return page->add(obj);
} public:
static inline id autorelease(id obj)
{
assert(obj);
assert(!OBJC_IS_TAGGED_PTR(obj));
id *dest __unused = autoreleaseFast(obj);
assert(!dest || *dest == obj);
return obj;
} static inline void *push()
{
if (!hotPage()) {
setHotPage(new AutoreleasePoolPage(NULL));
}
id *dest = autoreleaseFast(POOL_SENTINEL);
assert(*dest == POOL_SENTINEL);
return dest;
} static inline void pop(void *token)
{
AutoreleasePoolPage *page;
id *stop; if (token) {
page = pageForPointer(token);
stop = (id *)token;
assert(*stop == POOL_SENTINEL);
} else {
// Token 0 is top-level pool
page = coldPage();
assert(page);
stop = page->begin();
} if (PrintPoolHiwat) printHiwat(); page->releaseUntil(stop); // memory: delete empty children
// hysteresis: keep one empty child if this page is more than half full
// special case: delete everything for pop(0)
if (!token) {
page->kill();
setHotPage(NULL);
} else if (page->child) {
if (page->lessThanHalfFull()) {
page->child->kill();
}
else if (page->child->child) {
page->child->child->kill();
}
}
} static void init()
{
int r __unused = pthread_key_init_np(AutoreleasePoolPage::key,
AutoreleasePoolPage::tls_dealloc);
assert(r == 0);
} void print()
{
_objc_inform("[%p] ................ PAGE %s %s %s", this,
full() ? "(full)" : "",
this == hotPage() ? "(hot)" : "",
this == coldPage() ? "(cold)" : "");
check(false);
for (id *p = begin(); p < next; p++) {
if (*p == POOL_SENTINEL) {
_objc_inform("[%p] ################ POOL %p", p, p);
} else {
_objc_inform("[%p] %#16lx %s",
p, (unsigned long)*p, object_getClassName(*p));
}
}
} static void printAll()
{
_objc_inform("##############");
_objc_inform("AUTORELEASE POOLS for thread %p", pthread_self()); AutoreleasePoolPage *page;
ptrdiff_t objects = 0;
for (page = coldPage(); page; page = page->child) {
objects += page->next - page->begin();
}
_objc_inform("%llu releases pending.", (unsigned long long)objects); for (page = coldPage(); page; page = page->child) {
page->print();
} _objc_inform("##############");
} static void printHiwat()
{
// Check and propagate high water mark
// Ignore high water marks under 256 to suppress noise.
AutoreleasePoolPage *p = hotPage();
uint32_t mark = p->depth*COUNT + (uint32_t)(p->next - p->begin());
if (mark > p->hiwat && mark > 256) {
for( ; p; p = p->parent) {
p->unprotect();
p->hiwat = mark;
p->protect();
} _objc_inform("POOL HIGHWATER: new high water mark of %u "
"pending autoreleases for thread %p:",
mark, pthread_self()); void *stack[128];
int count = backtrace(stack, sizeof(stack)/sizeof(stack[0]));
char **sym = backtrace_symbols(stack, count);
for (int i = 0; i < count; i++) {
_objc_inform("POOL HIGHWATER: %s", sym[i]);
}
free(sym);
}
} #undef POOL_SENTINEL
};

  

https://opensource.apple.com/source/objc4/objc4-532/runtime/NSObject.mm.auto.html

@autoreleasepool

双向链表

Objective-C autoreleasepool深入理解的更多相关文章

  1. YYKit @autoreleasepool 使用,优化内存

    写在前面 最近再看YY大神的YYKit工具,发现在代码中经常使用@autoreleasepool,特别是在与for循环搭配使用的时候.刚开始很不能理解. 先有个概念: 自己创建的对象:使用 alloc ...

  2. objective-c(内存管理)

    本文主要记录objective-c 内存管理的知识点: 1.objective-c的对象都是分配内存在堆上,与C的mallock和C++的new类似,只有int等系统变量分配内存在栈上: 2.obje ...

  3. iOS - OC 内存管理

    1.OC 基本内存管理模型 1.1 自动垃圾收集 在 OC 2.0 中,有一种称为垃圾收集的内存管理形式.通过垃圾收集,系统能够自动监测对象是否拥有其他的对象,当程序执行需要空间的时候,不再被引用的对 ...

  4. [UWP] 对应用进行A/B测试

    [对A/B测试的看法] 开发者在Dev Center中设置几种应用变体,这几种变体有几个变量的值不一样,比如有变体A和变体B(当然还可以加上变体C,Dev Center最多支持5个变体),A和B的不同 ...

  5. Cocos2d-X3.0 刨根问底(四)----- 内存管理源码分析

    本系列文章发表以来得到了很多朋友的关注,小鱼在这里谢谢大家对我的支持,我会继续努力的,最近更新慢了一点,因为我老婆流产了抽了很多时间来照顾她希望大家谅解,并在此预祝我老婆早日康复. 上一篇,我们完整的 ...

  6. C --> OC with RunTime

    前言 本来打算写一篇关于runtime的学习总结,无奈长篇大论不是我的风格,就像写申论一样痛苦,加之网上关于tuntime的文章多如牛毛,应该也够童子们学习的了,今天就随便聊聊我的理解吧. runti ...

  7. Automake

    Automake是用来根据Makefile.am生成Makefile.in的工具 标准Makefile目标 'make all' Build programs, libraries, document ...

  8. Objective C内存管理之理解autorelease------面试题

    Objective C内存管理之理解autorelease   Autorelease实际上只是把对release的调用延迟了,对于每一个Autorelease,系统只是把该Object放入了当前的A ...

  9. 理解Objective C 中id

    什么是id,与void *的区别 id在Objective C中是一个类型,一个complier所认可的Objective C类型,跟void *是不一样的,比如一个 id userName, 和vo ...

随机推荐

  1. SSM+solr 通过商品搜索学习solr的简单使用

    学习了一下https://github.com/TyCoding/ssm-redis-solr这个github上的solr搜索功能,现在来记录一下. 我的理解就是solr有点类似于数据库,但它是有索引 ...

  2. nginx 匹配规则小总结

    nginx location 等号类型(=)的优先级最高,需要精确匹配.一旦匹配成功,则不再查找其他匹配项. ^~类型表达式.一旦匹配成功,则不再查找其他匹配项. 正则表达式类型(~ ~*)的优先级次 ...

  3. python2&python3

    1.Python3 使用 print 必须要以小括号包裹打印内容,比如 print('hi')   Python2 既可以使用带小括号的方式,也可以使用一个空格来分隔打印内容,比如 print 'hi ...

  4. D3.js 制作中国地图

    from:  http://d3.decembercafe.org/pages/map/index.html GeoJSON is a format for encoding a variety of ...

  5. 前端开发面试题-CSS(转载)

    本文由 本文的原作者markyun 收集总结. 介绍一下标准的CSS的盒子模型?低版本IE的盒子模型有什么不同的? (1)有两种, IE 盒子模型.W3C 盒子模型: (2)盒模型: 内容(conte ...

  6. [VUE ERROR] Invalid options in vue.config.js: "publicPath" is not allowed

    项目在build的时候报的这个错误: 具体原因是因为版本支持的问题,publicPath 属性到 vue-cli 3.2.0 之后才支持,所以将 publicPaht 改成 baseUrl 即可,或者 ...

  7. JavaScript大杂烩16 - 推荐实践

    JavaScript部分 1. 总是使用===来进行相等判断 原因:由于 == 和 != 操作符存在类型转换问题,而为了保持代码中数据类型的完整性,推荐使用全等 === 和不全等 !=== 操作符. ...

  8. 利用搜狐新闻语料库训练100维的word2vec——使用python中的gensim模块

    关于word2vec的原理知识参考文章https://www.cnblogs.com/Micang/p/10235783.html 语料数据来自搜狐新闻2012年6月—7月期间国内,国际,体育,社会, ...

  9. django 简单路由配置

    Django==2.0.1 版本路由配置: 1.在manage.py同级目录下新建一个应用app1 在app1下新建urls.py文件,定义一个app1的空白路由: from django.urls ...

  10. Linux的命名空间详解--Linux进程的管理与调度(二)【转】

    Linux Namespaces机制提供一种资源隔离方案. PID,IPC,Network等系统资源不再是全局性的,而是属于特定的Namespace.每个Namespace里面的资源对其他Namesp ...