1.对象的生成和引用计数
对象是在堆空间上的,alloc 创建内存区域 ,init 初始化内存区域,同时在栈空间上,我们会push 一个指针,指向对象的所存在的那个内存区域
2.对象的释放与循环引用
对象一般在方法结束之后会释放,如果循环引用之后,引用计数不会降为1,对象内部不会走dealloc方法,然而外面的栈指针已经释放了(&p 内存块已经释放了),但是堆里面的内存还相互引用着,所以会造成内存释放不了。
3.继承体系的内存分配
创建的的时候先 创建基类的相关属性和变量 ,释放的时候,先释放子类相关的属性和对象
4.Autorelease 技术
Autorelease 是延迟释放的技术 ,如果一个方法要返回一个对象 - (ObjectA *)objet ; Oj A *a = OjA alloc ]init]; return a ;如果在a返回之前 ,a release 释放了,程序会crash 。所以就引入了a autorelease 技术,先把autorelease的对象放在自动释放池中,如果调用 autoreleasePool drain] 方法会清空自动释放池。什么时候调用呢,下次run Loop 来到时。
这里又引出了一个Runloop的概念。对于每一个Runloop, 系统会隐式创建一个Autorelease pool,这样所有的release pool会构成一个象CallStack一样的一个栈式结构,在每一个Runloop结束时,当前栈顶的Autorelease pool会被销毁,这样这个pool里的每个Object会被release。那什么是一个Runloop呢? 一个UI事件,Timer call, delegate call, 都会是一个新的Runloop。
5.pool 与runloop
我们并不能自己创建runLoop , 通过alloc 的方式,对象为空。我们可以通过
@property(class,readonly,strong)NSRunLoop*currentRunLoop;
@property(class,readonly,strong)NSRunLoop*mainRunLoop;
获取到当前runloop
RunLoop和线程是一一对应的。必须先有线程,在使用该线程的RunLoop的第一次才完成其初始化,线程销毁时,RunLoop也随之销毁。
回到RunLoop与AutoreleasePool的关系,上节说了AutoreleasePool的机制,但没有说明具体的创建时机已经drain方法的调用时机,本节就可以给出答案了。RunLoop可以将自己的状态变化告知外界,具体是通过观察者模式实现的,状态变化后,观察者会收到通知,执行相应的代码。
在程序运行时打断点,可以通过po [NSRunLoop mainRunLoop]查看mainRunLoop的观察者,搜索autorelease可以找到相关的信息。App启动后,苹果在主线程 RunLoop 里注册了两个 Observer,其回调都是 _wrapRunLoopWithAutoreleasePoolHandler()。第一个 Observer 监视的事件是 Entry(即将进入Loop),其回调内会调用 _objc_autoreleasePoolPush() 创建自动释放池。其 order 是-2147483647,优先级最高,保证创建释放池发生在其他所有回调之前。第二个 Observer 监视了两个事件: BeforeWaiting(准备进入休眠) 时调用_objc_autoreleasePoolPop() 和 _objc_autoreleasePoolPush() 释放旧的池并创建新池;Exit(即将退出Loop) 时调用 _objc_autoreleasePoolPop() 来释放自动释放池。这个 Observer 的 order 是 2147483647,优先级最低,保证其释放池子发生在其他所有回调之后。
网友评论