美文网首页
iOS 管理内存的方式 - 用户态接口层面

iOS 管理内存的方式 - 用户态接口层面

作者: iOS小童 | 来源:发表于2019-12-05 13:37 被阅读0次

    内存消耗:内存消耗指的是RAM(随机存取存储器),应用中的内存消耗分为栈大小和堆大小。ROM(Read-Only Memory)即只读内存,是一种只能读出事先所存数据的固态半导体存储器

    • 栈大小:

      1. 可被递归调用的最大方法数:每个方法都有自己的栈桢,并会消耗整体的栈空间。
      2. 一个方法中最多可以使用的变量个数:所有的变量都会载入方法的栈桢中,并消耗栈空间。
      3. 视图层级中可以嵌入的最大视图深度:如果视图层级过深,可能会导致栈溢出。
    • 堆大小:

      1. 每个进程的所有线程公用同一个堆,应用并不能控制分配给它的堆,只有操作系统才能管理堆。
      2. 使用NSString、载入图片、创建和使用JSON数据、使用视图都会消耗大量的堆内存。
      3. 类可能包含一些实例变量(int,char),但因为对象是在堆内创建的,所以它们只消耗堆内存。
      4. 当对象被赋值时,数据可能会从栈复制到堆,或值在内部使用时,它们可能会从堆复制到栈。
    1. 自动释放池块:他能确保在块内创建的对象在块完成时被回收,尽早的释放其中的对象,从而使内存用量保持在较低的水平。AppKit和UIKit框架将事件-循环的迭代放入了autoreleasepool块中,所以自动释放池块无处不在。但在一些特定的情况下,还需要创建autoreleasepool块:
    • 当你有一个创建了很多临时对象的循环时。
    • 当你创建一个自定义线程时,必须创建autoreleasepool。
    1. ARC规则
    • 不能实现或者调用retain、release、autorelease、retainCount方法。
    • 可以实现dealloc方法,不能调用。
    • 不能调用NSAllocateObject和NSDeallocateObject方法。
    • 不能再c语言的结构体内使用对象指针。
    • 不能再id类型和void类型 *类型之间自动转换
    • 不能使用NSAutorelaesepool,要用autoreleasePool块。
    • 不能使用NSZone内存区域。
    1. 引用类型
    • 强引用:指向的内存不会被释放,应用计数加1,从而扩展对象的生命周期。
    • 弱引用:不会增加引用计数,从而不会扩展对象的生命周期。
    • 软引用:和弱引用相似,只是没有弱引用那么迫切的抛弃它所引用的对象,一般还能再坚持一会。
    • 幽灵引用:最弱的引用类型,会被最早的回收清理。
    1. 变量、属性限定符
    • strong:强引用,(浅拷贝) + 1,引用期间不会被回收。用于(对象、NSMutable...)。

    • weak:弱引用,+ 0,对象会立即释放,置nil。用于(Delegate)。

    • unsafe_unretained:与weak类似,只是不会被置nil,+ 1,对象会立即释放,但不会置nil。

    • autoreleasing:由引用使用id * 传递的消息参数,+ 1,对象会立即释放。

    • asign:只进行值复制而没有任何实质性的检查,用于(BOOl、NSInter、NSUInter等)。

    • copy:深拷贝,用于(NSString、NS...、Block)。

      weak和assign:weak只能修饰对象,不能修饰基本数据类型。而assign既可以修饰基本数据类型,也可以修饰对象。但一般用于修饰基本数据类型。因为当你用assgin修饰对象时候,如果你修饰的对象销毁,该指针的指向地址仍然存在。所以造成野指针。而这个野指针的内存在堆上,所以容易造成堆内存崩溃。而基本数据类型则存在于栈上,栈上内存系统会自动处理,不会造成野指针

      atomic和nonatomic:nonatomic是非原子性,就是可以多线程访问,效率高。而atomic,是原子性的,属于安全级别的,同一个时刻只能有同一个线程访问,具有对资源的独占性,当然,效率低。atomic会在线程中加一个锁,但并不是绝对安全的。

      copy和strong:copy修饰的都是不可变对象,copy拷贝的值为深拷贝,指针和对象拷贝一份新的,strong拷贝为浅拷贝,指针拷贝。修饰string对象时无差别

      __strong和__weak 我们一般不属于强引用某个对象的时候,可以使用__weak进行修饰,典型的例子就是代理,防止循环引用。在block内部,仅用__weak所修饰的对象,如果被释放,那么这个对象在Block执行的过程中就会变成nil,这就可能会带来一些问题,比如,数组,字典的插入,而__strong在Block内部修饰的对象,会保证,在使用这个对象在scope内,这个对象都不会被释放,出了scope就会释放。

    1. 循环引用

      常出现的循环引用:

    • 委托:delegate
    • 代理:block
    • 线程与计时器

    避免循环引用:

    • 对象不应该持有它的父对象,应用weak引用指向它的父对象。
    • 作为必然的结果,一个层级体系中的字对象应该保留祖先对象。
    • 连接对象不应该持有他们的目标对象。
    • 使用专用的销毁方法中断循环引用。
    1. 观察者
    • 键-值观察:addObserver:forKeyPath:options:context:方法在任何NSObject子类的对象上添加观察者,得到通知。
    • 通知中心:一个对象可以注册为通知中心(NSNotificationCenter)对象的观察者,并接收NSNotification对象。
    1. 对象寿命与泄漏

    尽量尽可能地避免出现长寿命的对象,也要不必每次都浪费时间来创建它们。所以合理使用单例和全局变量。

    单例应该满足(避免使用,会增加启动时间):

    • 队列操作(如日志和埋点)
    • 访问共享资源(如缓存)
    • 资源池(如线程池或链接池)

    全局变量必须满足:(少使用,占内存)

    • 没有被其他对象锁持有
    • 不是常量
    • 整个应用中只有一个。

    避免以上问题,合理应用属性去减少内存的消耗,降低平均和峰值内存。

    相关文章

      网友评论

          本文标题:iOS 管理内存的方式 - 用户态接口层面

          本文链接:https://www.haomeiwen.com/subject/kaydgctx.html