内存管理

2020-05-04  本文已影响0人  kakao6

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,优先级最低,保证其释放池子发生在其他所有回调之后。

上一篇下一篇

猜你喜欢

热点阅读