内存管理

2020-08-23  本文已影响0人  阿狸小朋友

autoreleasePool

App启动后,苹果在主线程 RunLoop 里注册了两个 Observer,其回调都是 _wrapRunLoopWithAutoreleasePoolHandler()。可以通过LLDB的po [NSRunLoop currentRunLoop]进行查看

在主线程执行的代码,通常是写在诸如事件回调、Timer回调内的。这些回调会被 RunLoop 创建好的 AutoreleasePool 环绕着,所以不会出现内存泄漏,开发者也不必显示创建 Pool 了。

当我们使用@autoreleasepool{}时,编译器会将其转换成以下形式

/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 
}

//__AtAutoreleasePool定义如下:
struct __AtAutoreleasePool {
  __AtAutoreleasePool() {atautoreleasepoolobj = objc_autoreleasePoolPush();}
    .
  ~__AtAutoreleasePool() {objc_autoreleasePoolPop(atautoreleasepoolobj);}
  void * atautoreleasepoolobj;
};
// `objc_autoreleasePoolPush()`最终会调用`autoreleaseFast()`压入`POOL_SENTINEL(哨兵对象)`,并返回哨兵地址方便`objc_autoreleasePoolPop`

void *
objc_autoreleasePoolPush(void)
{
    return AutoreleasePoolPage::push();
}
// 向晚于哨兵地址之后的对象发送`release`

void
objc_autoreleasePoolPop(void *ctxt)
{
    AutoreleasePoolPage::pop(ctxt);
}
//`autorelease`最终也是调用`autoreleaseFast()`,为了将对象加入`pool`中
    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;
    }

对象何时释放

  1. 手动添加的@autoreleasepool{},会在}结束的时候内部会调用objc_autoreleasePoolPop进行释放
  2. 添加到系统autoreleasepool的对象,会在runloop进入睡眠或者退出runloop的时候释放

内存

  1. https://mp.weixin.qq.com/s/r0Q7um7P1p2gIb0aHldyNw
  2. https://zhuanlan.zhihu.com/p/49829766

无论是打开网页,还是执行一段简单的 js 代码,UIWebView 都会占用大量内存,同时旧版本的 css 动画也会导致大量问题,所以最好使用 WKWebView。

内存泄漏

上一篇下一篇

猜你喜欢

热点阅读