9、内存管理初级
2015-11-14 16:52
239 查看
内存管理的⽅式
内存溢出
iOS给每个应⽤程序提供了⼀定的内存,⽤于程序的运⾏。iPhone 3GS内存30M左右,
iPhone 5S 内存80M左右。
⼀旦超出内存上限,程序就会Crash。
程序中最占内存的就是图⽚、⾳频、视频等资源⽂件。
3.5⼨⾮Retina屏幕(320 * 480)放⼀张全屏图⽚,占⽤字节数320 * 480 * 4(⼀个像素占4个字节,存放RGBA),即:600k Bytes。
iPhone 3GS同时读取60张图⽚就会crash。
4⼨屏幕(320 * 568 ),实际像素640 * 1136,程序存放⼀张全屏图⽚,占⽤字节数640 * 1136 * 4,即2.77M Bytes。
iPhone 5S同时读取40张图⽚就会crash。
野指针异常
对象内存空间已经被系统回收,仍然使⽤指针操作这块内存。野指针异常是程序crash的主要原因。代码量越⼤的程序,越难找出出现野指针的位置内存管理的⽅式
垃圾回收(gc)
程序员只需要开辟内存空间,不需要⽤代码显⽰地释放,系统来判断哪些空间不再被使⽤,并回收这些内存空间,以便再次分配。整个回收的过程不需要写任何代码,由系统⾃动完成垃圾回收。
Java开发中⼀直使⽤的就是垃圾回收技术
MRC(Manual Reference Count)⼈⼯引⽤计数
内存的开辟和释放都由程序代码进⾏控制。相对垃圾回收来说,对内存的控制更加灵活,可以在需要释放的时候及时释放,对程序员的要求较⾼,程序员要熟悉内存管理的机制。
ARC(Auto Reference Count)⾃动引⽤计数
iOS 5.0的编译器特性,它允许⽤户只开辟空间,不⽤去释放空间。它不是垃圾回收!它的本质还是MRC,只是编译器帮程序员默认加了释放的代码引⽤计数机制,影响计数的各个⽅法
C语⾔中,使⽤malloc和free,进⾏堆内存的创建和释放。堆内存只有正在使⽤和销毁两种状态。实际开发中,可能会遇到,两个以上的指针使⽤同⼀块内存。C语⾔⽆法记录内存使⽤者的个数。
OC采⽤引⽤计数机制管理内存,当⼀个新的引⽤指向对象时,引⽤计数器就递增,当去掉⼀个引⽤时,引⽤计数就递减。当引⽤计数到零时,该对象就将释放占有的资源。
影响引⽤计数的⽅法
+alloc
开辟内存空间,让被开辟的内存空间的引⽤计数变为1。这是由0到1的过程
-retain
引⽤计数加1,如果内存空间之前引⽤计数为1,ratain之后变为2,如果引⽤计数是5,retain之后变为6-copy
把某⼀内存区域的内容拷⻉⼀份,拷⻉到新的内存空间⾥去,被拷⻉区域的引⽤计数不变,新的内存区域的引⽤计数为1-release
引⽤计数减1,如果内存空间之前引⽤计数为4,release之后变为3,如果之前引⽤计数为1,release之后变为0,内存被系统回收。-autorelease
未来的某⼀时刻引⽤计数减1。如果内存之前引⽤计数为4,autorelease之后仍然为4,未来某个时刻会变为3
autoreleasepool
通过autoreleasepool控制autorelease对象的释放。向⼀个对象发送autorelease消息,这个对象何时释放,取决于autoreleasepool。
NSAutoreleasePool *pool= [[NSAutoreleasePool alloc]init]; Person *p = [[Person alloc]init];//retainCount为1 [p retain];//retainCount为2 [p autorelease];//retainCount为2 未来的某个时刻释放 [pool release];//此时autorelease的对象引⽤计数-1 NSLog(@”%d”,[p retainCount]);//打印结果为1
NSAutoreleasePool *pool= [[NSAutoreleasePool alloc]init];和[pool release];就像⼀对括号,[xxx autorelease];必须写在两者之间。
[xxx autorelease];出现在了两者之间,pool就会把接收autorelease的对象给保存起来(以栈的⽅式,把对象压⼊栈)
当[pool release];的时候,pool会向之前保存的对象逐⼀发送release消息(对象出栈,越晚autorelease的对象,越早接收release消息)。
在iOS5之后,不再推荐使⽤NSAutoreleasePool类,使⽤@autoreleasepool{}替代。
之前写在NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];和[pool release];之间的代码,需要写在@autoreleasepool{}的⼤括号⾥。
出了⼤括号,⾃动释放池才向各个对象发送release消息。
dealloc⽅法
-dealloc是继承⾃⽗类的⽅法,当对象引⽤计数为0的时候,由对象⾃动调⽤- (void)dealloc{ //验证对象引⽤计数是否降为0 NSLog(@“%@被销毁了”,self); [super dealloc]; }
内存管理的基本原则
引⽤计数的增加和减少相等,当引⽤计数降为0之后,不应该再使⽤这块内存空间凡是使⽤了alloc、retain或者copy让内存的引⽤计数增加了,就需要使⽤release或者autorelease让内存的引⽤计数减少。在⼀段代码内,增加和减少的次数要相等
内存管理的原则
1)原则
只要还有人在使用某个对象,那么这个对象就不会被回收; 只要你想使用这个对象,那么就应该让这个对象的引用计数器+1; 当你不想使用这个对象时,应该让对象的引用计数器-1;
2)谁创建,谁release
(1)如果你通过alloc,new,copy来创建了一个对象,那么你就必须调用release或者 autorelease方法
(2)不是你创建的就不用你去负责
3)谁retain,谁release
只要你调用了retain,无论这个对象时如何生成的,你都要调用release
4)总结
有始有终,有加就应该有减。曾经让某个对象计数器加1,就应该让其在最后-1.
掌握copy的实现
跟retain不同,⼀个对象想要copy,⽣成⾃⼰的副本,需要实现NSCopying协议,定义copy的细节(如何copy)。如果类没有接受NSCopying协议⽽给对象发送copy消息,会引起crashPerson.h⽂件
@interface Person : NSObject<NSCopying>//实现NSCopying协议 @property(nonatomic, retain)NSString *name; @property(nonatomic, assign)int age; @end
Person.m⽂件
@implementation Person //NSCopying协议必须实现的方法 -(id)copyWithZone:(NSZone *)zone{ //用[[Person alloc]init]也可以,建议使用以下,好看噻~ Person *p = [[Person allocWithZone:zone]init]; //成员变量的指针只是一个赋值作用,指向的是同一块内存,是浅拷贝,地址相同 /**/ p.name = self.name; p.sex = self.sex; p.age = self.age; NSLog(@"%p,%p",p.name,self.name); //深拷贝,重新分配内存,将原来内存中的内容放到新的内存中,地址不同 /* p.name = [[NSString alloc]initWithFormat:@"%@",self.name]; NSLog(@"%p,%p",p.name,self.name); */ return p; } @end
main.m文件
Person *p = [[Person alloc]init]; p.name = @”张三”; p.age = 20; Person *p2 = [p copy];//p2是p的副本,属于浅拷贝 //p2.name与p.name⼀样。p2.age与p.age⼀样。
相关文章推荐
- Teamviewer QuickSupport - 在电脑上远程连接控制手机/平板的软件神器 (Android/iOS)
- java开发环境 jdk环境变量配置
- 用qt creator,常量中有换行符的解决办法
- 用Excel表格裁剪圆角图片
- WifiManager、ScanResult(一)
- 双11引发的思考
- ubuntu15.04 无线上网问题
- Educational Codeforces Round 1(B)
- 拒绝升级win10
- 上传APP store 流程
- c++primer文本查询系统
- Java集合Set、Map、HashSet、HashMap、TreeSet、TreeMap等
- linux源的一些命令
- 配置cwrsync实现windows2008和centos7文件定时同步
- HDU - 1255 覆盖的面积(线段树求矩形面积交 扫描线+离散化)
- vsftpd服务的归纳总结
- 存储容器 隐式数据共享 可赋值数据类型
- 8、属性
- 我准备的C++面试题
- 简易员工信息系统