ios-内存管理


为什么管理内存:

程序在运行的时候,要创建大量的对象,这些对象放在堆和栈上。(基本类型放在栈上,由系统自动管理。) 而放在堆上的对象如果得不到及时释放,就会占用大量内存。OC中没有垃圾回收机制,所以我们要手动管理内存(ARC之前)

原理:

依赖对象引用计数器+1 -1:在ObjC中对象创建后内部都有一个与之对应的整数(retainCount),叫“引用计数器”,当一个对象在创建之后它的引用计数器为1,当调用这个对象的alloc、retain、new、copy方法之后引用计数器自动在原来的基础上加1(ObjC中调用一个对象的方法就是给这个对象发送一个消息),当调用这个对象的release方法之后它的引用计数器减1,如果一个对象的引用计数器为0,则系统会自动调用这个对象的dealloc方法来销毁这个对象。


原则:

谁创建,谁释放,谁引用,谁管理。


自动释放池:

autorelease方法不会改变对象的引用计数器,只是将这个对象放到自动释放池中;

自动释放池(@autoreleaespool)实质是当自动释放池销毁后调用对象的release方法,不一定就能销毁对象(例如如果一个对象的引用计数器>1则此时就无法销毁);

由于自动释放池最后统一销毁对象,因此如果一个操作比较占用内存(对象比较多或者对象占用资源比较多),最好不要放到自动释放池或者kao虑放到多个自动释放池;

自动释放池是什么,如何工作

当您向一个对象发送一个autorelease消息时,将该对象的一个引用放入到最新的

自动释放池。它仍然是个正当的对象,因此自动释放池定义的作用域内的其它对

象可以向它发送消息。当程序执行到作用域结束的位置时,自动释放池就会被释

放,池中的所有对象也就被释放。



什么是ARC:

官方定义:“自动引用计数(ARC)是一个编译器级的功能,它能简化Cocoa应用中对象生命周期管理(内存管理)的流程。” 

Automatic Reference Counting,自动引用计数,即ARC

ARC编译器有两部分,分别是前端编译器和优化器

当ARC开启时,编译器将自动在代码合适的地方插入retain, release和autorelease

ARC优化器---当代码中出现多个对 retain 和release的重复调用,ARC优化器负责移出多余的 retain 和release语句。确保生成的代码运行速度高于手动引用计数的代码。

如果涉及到较为底层的东西,比如Core Foundation中的malloc()或者free()等,ARC就鞭长莫及了,这时候还是需要自己手动进行内存管理

打开ARC:-fobjc-arc

关闭ARC:-fno-objc-arc


关键字:

@property的参数分为三类,也就是说参数最多可以有三个

程序会使用三类中的各个默认参数,默认参数:(atomic,readwrite,assign)

atomic 对属性加锁,多线程下线程安全,默认值 加同步 是防止在写未完成的时候被另外一个线程读取,造成数据错误。而这种机制是耗费系统资源的。对于对象的默认属性,就是setter/getter生成的方法是一个原子操作。

如果有多个线程同时调用setter的话,不会出现某一个线程执行setter全部语句

之前,另一个线程开始执行setter的情况,相关于方法头尾加了锁一样。

nonatomic 对属性不加锁,多线程下不安全,但速度快 不加同步,多线程并发访问会提高性能。

readwrite 默认属性,将生成不带额外参数的getter和setter方法(setter方法只有一个参数)。

readonly  将只生成getter方法而不生成setter方法(getter方法没有get前缀)。

assign 基本的赋值、直接赋值,默认值 不更改索引计数(Reference Counting).使用assign: 对基础

数据类型 (NSInteger)和C数据类型(int, float, double, char,等)

retain 让对象引用计数+1,表示拥有这个对象,先release原来的值,在retain新值

copy 先release原来的值,在copy新值 建立一个索引计数为1的对象,然后释放旧对象

retain是指针拷贝,copy是内容拷贝。(可以理解为retain是浅拷贝,copy是深拷贝。)

strong 强引用,strong关键字与retain关似,用了它,引用计数自动+1,有strong指向的对象不会被释放

weak 弱引用,声明为weak的指针,指针指向的地址一旦被释放,这些指针都将被赋值为nil。这样的好处能有效的防止野指针。声明了一个可以自动 nil 化的弱引用

当weak指向的内存释放掉后自动置为nil,防止野指针。

unsafe_unretained声明的指针,由于 self.string1=nil已将内存释放掉了,但是string2并不知道已被释放了,所以是野指针。然后访问野指针的内存就造成crash. 声明一个弱应用,但是不会自动nil化,也就是说,如果所指向的内存区域被释放了,这个指针就是一个野指针了。

static  一般情况下,只能用NSString或者基本类型 都是私有的,通常在单例中使用

assign,用于基本数据类型

retain,通常用于非字符串对象 对其他NSObject和其子类 

copy,通常用于字符串对象、block、NSArray、NSDictionary

copy是创建一个新对象,retain是创建一个指针,引用对象计数加1

强引用也就是我们通常所讲的引用,其存亡直接决定了所指对象的存亡。如果不存在指向一个对象的引用,并且此对象不再显示列表中,则此对象会被从内存中释放。

  弱引用除了不决定对象的存亡外,其他与强引用相同。即使一个对象被持有无数个若引用,只要没有强引用指向他,那麽其还是会被清除。

static 关键字的作用:

函数体内 static 变量的作用范围为该函数体,不同于 auto 变量,该变量的内存只被分配一次,

因此其值在下次调用时仍维持上次的值;

在C语言中,关键字static有三个明显的作用:

1). 在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。

2). 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。

3). 在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用。

关键字const有什么含意?修饰类呢?static的作用,用于类呢?还有extern c的作用

const 意味着"只读",下面的声明都是什么意思?  

const int a;  

int const a;  

const int *a;  

int * const a;  

int const * a const; 

前两个的作用是一样,a是一个常整型数。

第三个意味着a是一个指向常整型数的指针(也就是,整型数是不可修改的,但指

针可以)。

第四个意思a是一个指向整型数的常指针(也就是说,指针指向的整型数是可以修

改的,但指针是不可修改的)。

最后一个意味着a是一个指向常整型数的常指针(也就是说,指针指向的整型数是

不可修改的,同时指针也是不可修改的)。

结论:

 关键字const的作用是为给读你代码的人传达非常有用的信息,实际上,声明一个参数为常量是为了告诉了用户这个参数的应用目的。如果你曾花很多时间清理其它人留下的垃圾,你就会很快学会感谢这点多余的信息。(当然,懂得用const的程序员很少会留下的垃圾让别人 来清理的。)   通过给优化器一些附加的信息,使用关键字const也许能产生更紧凑的代码。  

 合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数,防止其被无意的代码修改。简而言之,这样可以减少bug的出  现。  

(1)欲阻止一个变量被改变,可以使用 const 关键字。在定义该 const 变量时

,通常需要对它进行初始化,因为以后就没有机会再去改变它了; 

(2)对指针来说,可以指定指针本身为 const,也可以指定指针所指的数据为 

const,或二者同时指

定为 const; 

(3)在一个函数声明中,const 可以修饰形参,表明它是一个输入参数,在函数

内部不能改变其值; 

(4)对于类的成员函数,若指定其为 const 类型,则表明其是一个常函数,不

能修改类的成员变量; 

(5)对于类的成员函数,有时候必须指定其返回值为 const 类型,以使得其返

回值不为“左值”。

volatile有什么含意?并给出三个不同的例子。

一个定义为 volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。

精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。

下面是volatile变量的几个例子: 

并行设备的硬件寄存器(如:状态寄存器)  

一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)  

多线程应用中被几个任务共享的变量

ios的@property属性和@synthesize属性:

//当编译器遇到@property时,会自动展开成getter和setter的声明

@property int age;

@property int no;

//@synthesize 会自动生成getter和setter的实现

//@synthesize 默认会去访问age,no,height同名的变量,

//如果找不到同名的变量,会在内部自动生成一个私有同名变量age,no,height,,

//因此Student.h 中的这几个变量也可以省略不写。

@synthesize age,no;

1.在Xcode4.5及以后的版本中,可以省略@synthesize ,编译器会自动帮你加上getter 和 setter 方法的实现,并且默认会去访问_age这个成员变量,如果找不到_age这个成员变量,会自动生成一个叫做 _age的私有成员变量。



ios中的成员变量定义在@interface 和@implementation 中的区别是什么?

定义在@interface中是指定义在头文件里, 定义在@implementation中是指在实现文件中的类扩展(Class Extensions), 一般来说把要gong开的信息(变量,属性,方法)定义在头文件里, 把要隐藏的信息定义在类扩展里,只是为了隐藏私有信息, 不需要被外界知道的就不要放在头文件里, 这样可以隔离接口和实现。


堆和栈?

对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来讲,释放工作有程序员控制,容易产生memory Leak。

1.申请方式:stack:由系统自动分配。heap:需要程序员自己申请。

2.申请后系统的响应

栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。

堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,

3.申请大小的限制:

栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,大小有限制。

堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址

4.申请效率的比较:

栈由系统自动分配,速度较快。

堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,

5.堆和栈中的存储内容

6.存取效率的比较:

栈的效率比较高

堆和栈的区别?

堆是程序员控制的,栈是编辑器自动管理,栈是一块连续的内存区域,是向低地址扩展的数据结构,堆是向高低直落站的数据结构。

管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生memory leak。

申请大小:

栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。

堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。

碎片问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出

分配方式:堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。

分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的。




参kao文献:

http://www.cnblogs.com/kenshincui/p/3870325.html#autoid-2-1-0

http://mobile.51cto.com/iphone-386301.htm

http://blog.youkuaiyun.com/getchance/article/details/42213219

http://www.cnblogs.com/csj007523/archive/2012/07/23/2605662.html

http://www.cnblogs.com/thinksasa/p/3441551.html





转载于:https://my.oschina.net/liuchuanfeng/blog/659073

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值