内存管理初级

来源:互联网 发布:21端口被占用 编辑:程序博客网 时间:2024/06/02 13:21

iOS应⽤程序出现Crash(闪退),90%以上的原因是内存问题。


在⼀个拥有数⼗个甚⾄是上百个类的⼯程⾥,查找内存问题极其困难。了解内存常⻅问题,能帮我们减少出错⼏率。

内存问题体现在两个⽅⾯:内存溢出、野指针异常。


对象内存空间已经被系统回收,仍然使⽤指针操作这块内存。野指针异常是程序crash的主要原因。代码量越⼤的程序,越难找出出现野指针的位置。

了解内存管理,能帮我们提升程序性能,⼤⼤减少调试bug时间。


垃圾回收:程序员只需要开辟内存空间,不需要⽤代码显⽰地释放,系统来判断哪些空间不再被使⽤,并回收这些内存空间,以便再次分配。整个回收的过程不需要写任何代码,由系统⾃动完成垃圾回收。Java开发中⼀直使⽤的就是垃圾回收技术。


Manual Reference Count,⼈⼯引⽤计数:内存的开辟和释放都由程序代码进⾏控制。相对垃圾回收来说,对内存的控制更加灵活,可以在需要释放的时候及时释放,对程序员的要求较⾼,程序员要熟悉内存管理的机制。


Auto Reference Count,⾃动引⽤计数:iOS 5.0的编译器特性,它允许⽤户只开辟空间,不⽤去释放空间。它不是垃圾回收!它的本质还是MRC,只是编译器帮程序员默认加了释放的代码。


iOS⽀持两种内存管理⽅式:ARC和MRC。
MRC的内存管理机制是:引⽤计数。
ARC是基于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,内存被系统回收。


-dealloc是继承⾃⽗类的⽅法,当对象引⽤计数为0的时候,由对象⾃动调⽤。


-autorelease:未来的某⼀时刻引⽤计数减1。如果内存之前引⽤计数为4,autorelease之后仍然为4,未来某个时刻会变为3。


引⽤计数的增加和减少相等,当引⽤计数降为0之后,不应该再使⽤这块内存空间。凡是使⽤了alloc、retain或者copy让内存的引⽤计数增加了,就需要使⽤release或者autorelease让内存的引⽤计数减少。在⼀段代码内,增加和减少的次数要相等。

copy方法

-跟retain不同,⼀个对象想要copy,⽣成⾃⼰的副本,需要实现NSCopying协议,定义copy的细节(如何copy)。如果类没有接受NSCopying协议⽽给对象发送copy消息,会引起crash。

Student类copy方法的实现

Student.h文件

@interface Student :NSObject<NSCopying>

@property (nonatomic ,retain)NSString *name;

@property (nonatomic)NSInteger age;

@end


Student.m文件

@implementation Student

- (id)copyWithZone:(NSZone *)zone{

    Student *stu = [[StudentallocWithZone:zone]init];

    stu.age =self.age;

    stu.name =self.name;

    return stu;

}

//重写dealloc方法

- (void)dealloc{

    NSLog(@"空间马上销毁");

    [superdealloc];

}

@end


main.m文件

Student *stu = [[Studentalloc]init];

        stu.name =@"张三";

        stu.age =20;

        Student *stu1 = [stucopy];//stu1是stu的副本

        NSLog(@"%@",stu1.name);//stu1.name 和stu.name一样

        NSLog(@"%ld",(long)stu1.age);//stu1.age和stu.age一样

        [stu release];//释放

        [stu1 release];//释放


0 0