标签:
我们的iOS APP 出现Crash(闪退),90%以上的原因是内存问题。我们使用Xcode编译运行程序时常见到的一个EXC_BAD_ACCESS问题就是个典型的内存错误--访问了一块僵尸内存,当然这里不对僵尸内存进行深入讨论。那么内存问题主要体现在哪些方面呢,那就是“内存溢出”和“野指针异常”。
内存溢出
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。
所以说初学者在开发App时,使用图片一定要谨慎,注意性能。
野指针异常
对象内存空间已经被系统回收,仍然使?指针操作这块内存。野指针异常是程序crash的主要原因。代码量越?的程序,越难找出出现野指针的位置。
垃圾回收(gc):java;
在垃圾回收机制下程序员只需要开辟内存空间,不需要?代码显?地释放,系统来判断哪些空间不再被使?,并回收这些内存空间,以便再次分配。整个回收的过程不需要写任何代码,由系统?动完成垃圾回收。Java开发中?直使?的就是垃圾回收技术。
OC中有也gc机制,但是在IOS和MAC OS 10.4以后被苹果禁用。
人工引用计数MRC(Manual Reference Count):
内存开辟和释放都由程序代码控制。相对垃圾回收来说,对内存的控制更加灵活,可以在需要释放的时候及时释放,对程序员的要求较?,程序员要熟悉内存管理的机制。
特点:相对gc内存控制更灵活,对程序员要求高
自动引用计数ARC ( Auto Reference Count ) :
iOS 5.0 的编译器特性,允许用户只开辟空间,不用释放空间。但ARC不是垃圾回收!它的本质还是MRC,只是编译器帮程序员默认加了释放(release)的代码。
在C语言中,我们使用malloc和free来管理堆内存的创建和释放。堆内存也只有正在使用和销毁这两种状态。然而在实际的开发中,我们可能会遇到两个以上的指针指向同一块内存,这时C语言就无法记录这一块内存使用者的个数。Obj-C中采用的引用计数机制则很好地解决了这个问题。
OC采?引?计数机制管理内存,当?个新的引?指向对象时,引?计数器就递增,当去掉?个引?时,引?计数就递减。当引?计数到零时,该对象就将释放占有的资源。
影响引用计数的方法
+ alloc :开辟内存空间,让被开辟的内存空间的引用计数+1,这是0到1的过程。
(只有在见到alloc的时候才会开辟内存空间),
在类方法中无法使用实例变量、无法调用实例方法,因为还没有开辟内存空间
- retain :引用计数加1, 返回对象本身
- copy :把某?内存区域的内容拷??份,拷?到新的内存空间?去,原被拷?区域的引?计数不变,新的内存区域的引?计数为1。
- release : 引?计数减1。release之后配合nil使用可以安全释放。
- dealloc : 继承自父类的方法,当对象引用计数为0时,由对象自动调用。
- autorelease :在autoreleasepool中,不立即执行retain减1。
以下是个代码实例demo,只是为了列出知识点,如果不注释一些代码块可能无法运行:
main.m
#import <Foundation/Foundation.h> #import "Person.h" #import "Student.h" #define RELEASE_SAFE(_point) [_point release];_point = nil; int main(int argc, const char * argv[]) { //自动释放池 //是一种栈结构,每当遇到一个autorelease就将他入栈 //当出了自动释放池,将栈中所有对象引用计数减一 @autoreleasepool { //p1的引用计数为1 Person *p1 = [[Person alloc] init]; NSLog(@"%ld",[p1 retainCount]); //retain Person *p2 = [p1 retain]; NSLog(@"%ld",[p2 retainCount]); // Person *p3 = [p1 copy]; // NSLog(@"%ld",[p3 retainCount]); [p1 release]; NSLog(@"%ld",[p1 retainCount]); [p2 release]; //retainCount不记录0 NSLog(@"%ld",[p2 retainCount]); //引用计数为1 Person *p1 = [[Person alloc] init]; //引用计数为2 Person *p2 = [p1 retain]; //引用计数为1 [p1 release]; //安全释放 p1 = nil; //引用计数为0 //这个release没有效果 [p1 release]; //利用带参宏便捷,安全地释放空间 RELEASE_SAFE(p2); Person *p1 = [[Person alloc] init]; Person *p2 = [[Person alloc] init]; p1.name = @"庞麦龙"; p1.books = @[@"十万个冷笑话",@"尸兄"]; // [p1 retain]; //autorelease不会立即对引用计数减一 //离开自动释放池后,引用计数减一 [p1 autorelease]; [p2 autorelease]; // NSLog(@"%ld",[p1 retainCount]); } //凡是一次alloc,配套一次release或者autorelease //凡是一次retain,配套一次release或者autorelease //凡是一次copy,配套一次release或者autorelease //谁污染谁治理 Person *p1 = [[Person alloc] init]; Person *p2 = [p1 copy]; p1.name = @"如花"; p2.name = @"铁柱"; NSLog(@"%@",p2.name); RELEASE_SAFE(p2); RELEASE_SAFE(p1); [p1 copy]; Student *s1 = [[Student alloc] init]; s1.name =@"xuesheng"; s1.age = 1; Person *s2 = [s1 copy]; s2.name = @"taibao"; NSLog(@"%@",s1.name); RELEASE_SAFE(s2); RELEASE_SAFE(s1); /* *不建议使用实例对象的方式建立AutoreleasePool */ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; //池区,无作用域问题,autorelease的对象需要使用安全释放 Person *p1 = [[Person alloc] init]; [p1 autorelease]; [pool release]; pool = nil; p1 = nil; return 0; }
Person.h
#import <Foundation/Foundation.h> @interface Person : NSObject<NSCopying> @property(nonatomic,copy)NSString *name; @property(nonatomic,retain)NSArray *books; @end
Person.m
#import "Person.h" @implementation Person //销毁对象 - (void)dealloc { //当对象引用计数为0时,自动调用dealloc方法 NSLog(@"啊,I‘m over!"); //在一个对象销毁之前,清楚自己实例变量指向的内存 [_name release]; [_books release]; //最后销毁从父类继承的东西 [super dealloc]; } - (id)copyWithZone:(NSZone *)zone{ //浅拷贝 // return [self retain]; //深拷贝 Person *p = [[Person allocWithZone:zone] init]; p.name = [NSString stringWithFormat:@"%@",self.name]; p.books = [NSArray arrayWithArray:self.books]; return p; } @end
Student.h
#import <Foundation/Foundation.h> @interface Student : NSObject<NSCopying> @property(nonatomic,copy)NSString *name; @property(nonatomic,assign)NSInteger age; @end
Student.m
#import "Student.h" @implementation Student - (void)dealloc{ [_name release]; [super dealloc]; } - (id)copyWithZone:(NSZone *)zone{ Student *s = [[Student allocWithZone:zone] init]; s.name = [NSString stringWithFormat:@"%@",_name]; s.age = _age; return s; } @end
autoreleasepool是一个栈空间
凡是一次alloc,配套一次release或者autorelease
凡是一次retain,配套一次release或者autorelease
凡是一次copy,配套一次release或者autorelease
谁污染谁治理
标签:
原文地址:http://www.cnblogs.com/yilei/p/4241052.html