堆内存跟栈内存的介绍
栈区(stack):由编译器自动分配释放,函数的参数值,局部变量等值,栈内存的内存地址是连续的,自上而下申请内存,先进 后出,后进先出的原则,类似于数据结构中的线性表,用于存储函数的参数,局部变量,基本变量以及函数的调用堆栈等。
堆区(heap):一般由开发人员分配释放,若不释放,则可能会引起内存泄漏,堆内存的内存地址为不连续的,自下而上申请内存,先进先出,后进后出,类似于数据结构中的链表,用于存储iOS中被alloc的对象。
本文主要讲解个人开发多年以来对于内存管理的理解,如有说的不清楚的地方,还望指正交流。本文中的内存管理指堆内存的管理。
说到手机或者电脑的运行,就离不开内存管理,那么究竟什么是内存,内存在计算机中分为两种,一种是运行存储,一种是外置存储,像我们的操作系统,APP都是存放在外置存储中,外置存储一般指的是硬盘,移动硬盘,U盘等,用于存放需要持久化存储的数据,如操作系统,APP,照片,MP3,MP4等。
那么什么是运行存储呢,运行存储指操作系统在运行时,需要动态的去向内存条申请数据需要用到的存储媒介,主要是硬盘跟cpu之间传输数据的纽带。
在iOS中主要分为mrc内存管理,以及arc内存管理,mrc内存管理是在早期iOS开发用到的,因为堆内存讲究的是谁分配,谁释放,在app不退出的情况下,堆内存中的内存空间会一直存在,所以需要手动去释放。而arc中内存管理由系统来控制,通过引用计数器的方式自动的去做内存的管理
引用计数器
对象是否需要销毁,编译器通过引用计数器来判断,当对象被创建时,它的引用计数器为1,当其他对象强持有该对象时,该对象的引用计数器会加一,当持有它的对象被销毁时,它的引用计数器会减去1,当它的引用计数器为0时,它就会被编译器回收。
在iOS中继承自NSObject类的对象被new或者alloc后,才会被分配内存,此时该对象的引用计数器为1,当被strong修饰后,strong会拥有对象的所属权,对象的引用计数器会被加1,weak不会拥有对象的所属权,对象的引用计数器不会被增加,常用于解决循环引用,如代理跟block场景
内存修饰符
strong场景:
需要强持有对象的场景,可以使用strong修饰,但要注意循环引用导致内粗泄漏的问题
weak场景:
主要解决循环引用问题,当使用到代理或者block时,可以使用weak修饰。
copy场景:
copy的对象均为不可变对象,当copy不可变对象时,会进行浅拷贝,当copy可变对象时,会进行深拷贝
mutableCopy场景:
mutableCopy的对象均为可变对象,均为深拷贝
nonatomic跟atomic区别
atomic
原子性,线程不安全
优点
多线程操作同一属性时,set跟get是按照顺序执行的
缺点
因为会对属性加锁,所以会消耗系统资源,运行速度慢
noatomic
非原子性,线程安全
优点
运行速度快,不消耗系统资源
缺点
多线程操作同一属性时,会发生不可预知的错误