Objective-C autoreleasepool深入理解
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深入理解的更多相关文章
- YYKit @autoreleasepool 使用,优化内存
写在前面 最近再看YY大神的YYKit工具,发现在代码中经常使用@autoreleasepool,特别是在与for循环搭配使用的时候.刚开始很不能理解. 先有个概念: 自己创建的对象:使用 alloc ...
- objective-c(内存管理)
本文主要记录objective-c 内存管理的知识点: 1.objective-c的对象都是分配内存在堆上,与C的mallock和C++的new类似,只有int等系统变量分配内存在栈上: 2.obje ...
- iOS - OC 内存管理
1.OC 基本内存管理模型 1.1 自动垃圾收集 在 OC 2.0 中,有一种称为垃圾收集的内存管理形式.通过垃圾收集,系统能够自动监测对象是否拥有其他的对象,当程序执行需要空间的时候,不再被引用的对 ...
- [UWP] 对应用进行A/B测试
[对A/B测试的看法] 开发者在Dev Center中设置几种应用变体,这几种变体有几个变量的值不一样,比如有变体A和变体B(当然还可以加上变体C,Dev Center最多支持5个变体),A和B的不同 ...
- Cocos2d-X3.0 刨根问底(四)----- 内存管理源码分析
本系列文章发表以来得到了很多朋友的关注,小鱼在这里谢谢大家对我的支持,我会继续努力的,最近更新慢了一点,因为我老婆流产了抽了很多时间来照顾她希望大家谅解,并在此预祝我老婆早日康复. 上一篇,我们完整的 ...
- C --> OC with RunTime
前言 本来打算写一篇关于runtime的学习总结,无奈长篇大论不是我的风格,就像写申论一样痛苦,加之网上关于tuntime的文章多如牛毛,应该也够童子们学习的了,今天就随便聊聊我的理解吧. runti ...
- Automake
Automake是用来根据Makefile.am生成Makefile.in的工具 标准Makefile目标 'make all' Build programs, libraries, document ...
- Objective C内存管理之理解autorelease------面试题
Objective C内存管理之理解autorelease Autorelease实际上只是把对release的调用延迟了,对于每一个Autorelease,系统只是把该Object放入了当前的A ...
- 理解Objective C 中id
什么是id,与void *的区别 id在Objective C中是一个类型,一个complier所认可的Objective C类型,跟void *是不一样的,比如一个 id userName, 和vo ...
随机推荐
- webpack4 系列教程(九): CSS Tree Shaking
教程所示图片使用的是 github 仓库图片,网速过慢的朋友请移步原文地址 有空就来看看个人技术小站, 我一直都在 0. 课程介绍和资料 本次课程的代码目录(如下图所示): >>> ...
- MEF 插件式开发之 DotNetCore 初体验
背景叙述 在传统的基于 .Net Framework 框架下进行的 MEF 开发,大多是使用 MEF 1,对应的命名空间是 System.ComponentModel.Composition.在 Do ...
- kafka安装与简单使用
一.kafka安装 安装是非常简单的,现在推荐安装0.8的版本,这个版本是非常稳定的,而且公司里面也多用此版本. 简单的安装: 这个是我使用的版本,kafka_2.11-0.8.2.2.tgz 直接t ...
- VUE页面刷新问题
1). location方式 location.reload() 缺点:刷新页面,卡白 2). router方式 this.$router.go(0) 缺点:同一问题,比一好点 3). provide ...
- video 铺满父元素(object-fit: fill;)
遇到这个属性,是在给video 嵌入一个div时,导致video播放器上下有灰色.在控制台查看video默认样式的时候看到了这个属性. 播放器上下的灰色,不是我们想要的样式,如果能完全覆盖就更好了. ...
- Android basics
只要是Android中的控件,最终都继承自View.
- Fiddler抓包使用教程-过滤
转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/72929800 本文出自[赵彦军的博客] Fiddler抓包可以完成我们移动开发者的 ...
- HttpClient与浏览器调用服务接口差异
我用httpclient访问接口,统计图有些不均匀,差距较大 ,有时只有几十毫秒,下图看到这种情况占多数,600-800毫秒之间的算是浏览器正常的产生调用接口的时间耗时 然后用jmeter跑时都是均值 ...
- 洗礼灵魂,修炼python(60)--爬虫篇—httplib2模块
这里先要补充一下,Python3自带两个用于和HTTP web 服务交互的标准库(内置模块): http.client 是HTTP协议的底层库 urllib.request 建立在http.clien ...
- ABAP性能和优化
哪些工具可以用于性能优化? ST05-性能追踪.包含SQL追踪加RFC,队列和缓存追踪.SQL追踪主要用于测量程序中select语句的性能. SE30-运行时分析.用于测量应用的性能. SAT是过时的 ...