码迷,mamicode.com
首页 > 其他好文 > 详细

Obj-C内存管理初级

时间:2015-01-22 12:28:43      阅读:265      评论:0      收藏:0      [点我收藏+]

标签:

内存管理初级


为什么要管理内存

  我们的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)的代码。


OC内存管理机制

  在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

谁污染谁治理

Obj-C内存管理初级

标签:

原文地址:http://www.cnblogs.com/yilei/p/4241052.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!