手动内存

为什么要内存管理?

因为内存一直被占用的话,内存最终会不够用。

内存管理好处,1G可以运行3G应用,只要使用时不超过1G,及时释放的话。

一.oc中采用“引用计数”(retainCount)方式管理对象所占内存(内存有指针指向的概念)。

  1. alloc为对象分配内存。dealloc为对象释放所占内存,不能手动调用。
  2. 使用alloc、new对象时,并将其引用计数器设为1,并拥有对象所有权。
  3. copy制造一个副本,并将副本的引用计数设为1,对原有的引用计数不影响,并拥有副本对象所有权。
  4. retain使引用计数加1,并拥有对象所有权。release使引用计数减1,并放弃对象所有权。
  5. 当对象的retainCount为0时,系统自动调用dealloc释放对象内存;否则,分配内存将一直被占用。
  6. autorelrease向NSAutoreleasepool注册。

二.

  1. 引用计数:计内存的使用次数(内存被用了多少次)
  2. 所有权对象分为:程序员和系统。谁retain,所有权归谁。  NSString *sonCar = [mamaCar retain];//儿子有所有权,此时retain引用计数+1了,使用完后销毁不会出现野指针  NSString *friendCar = sonCar;//朋友没有使引用计数加1,也就是说当引用计数为0,对象销毁的时候,会出现friendCar这个野指针
  3. 消息(方法)是有延迟的,系统回收可能存在延迟,因为系统回收是以轮询的方式。就像现实中的保洁工人收垃圾。
  4. 引用计数为0是打印不出来的,因为0代表没有该对象了,所以retain方法调用不出来,这时候系统只能打印出1。
  5. 原则使用后立即释放。

三.属性中内存管理

  1. 原则:一个类中,如果这个类有属性声明retain或者copy的属性,那么我们需要在这个类的dealloc方法里释放一次。
  2. 属性内存管理分析图
  3. 属性的赋值方式:
  • 先初始化对象a
  • b.a = a;
  • [a release];

四.便利构造器内存管理

  1. 通过使用autorelease延迟release来管理构造器的对象。return [对象 autorelease];或@autoreleasepool{}
  2. NSAutoreleasePool自动释放池:
  • 当创建的对象未来某个时候销毁时,可以使用对象的autorelease。
  • 对象将所有权管理交给最近的NSAutoreleasePool对象,并由其全权管理。栈式结构(UINavigationController和图形上下文)
  • 当池对象drain或release时,会逐一对池内对象发送release消息。
  • 能不使用,尽量不使用aoturelease。知道什么时候用完,直接release。
  • 任何OC对象只要调用autorelease方法,就会把该对象放到离自己最近的自动释放池中(栈顶的释放池)

五.检测工具

  1. static Analyzer-Analysis Policy
  2. product-》profile-》leaks

六.类中self点出来的属性。需要autorelease。dealloc中不用[_xxxx release]。

相反:_xxxx = [[**  alloc]init];的属性在dealloc中[_xxxx release];。不用autorelease。


 Teacher.h

@interface Teacher : NSObject
-(void)onClass;
@end

Teacher.m

#import "Teacher.h"

@implementation Teacher
-(void)onClass
{
    NSLog(@"teacher is on class");
}
@end

Student.h

#import "Teacher.h"
@interface Student : NSObject
{
    Teacher *_teacher;
}

//@property(nonatomic,retain)Teacher *teacher;
-(void)setTeacher:(Teacher *)aTeacher;
-(Teacher *)teacher;
@end

Student.m

#import "Student.h"

@implementation Student

//@synthesize teacher = _teacher;
//retain中@synthesize默认手动写法
-(void)setTeacher:(Teacher *)aTeacher
{
    if (_teacher != aTeacher)//旧对象不等于新对象的时候-赋新值
    {
        [_teacher release];//_teacher释放?第一次_teacher是nil(对nil release没影响),但是如果后面还要把对象赋给_teacher的话,这里必须先释放(对上次传入的对象先进行释放并放弃所有权)
        _teacher = [aTeacher retain];//把所有权给_teacher。copy的话这里也改为[aTeacher retain]
        
    }
}
-(Teacher *)teacher
{
    return _teacher;
}



-(Student *)init
{
    self = [super init];
    if (self)
    {
        
    }
    return self;
}

//重写
-(void)dealloc
{
    [_teacher release];//属性中retain,这里也要release
    NSLog(@"我(%@)快要被释放了。。。。。",self);

  [super dealloc];//第一步必须做的,保留父类释放
} @end

AppDelegate.m

 /*
    Student *s = [[Student alloc]init];
    NSLog(@"reatinCount = %d",s.retainCount);
    
    [s retain];
    NSLog(@"reatinCount = %d",s.retainCount);
    
    [s release];
    NSLog(@"reatinCount = %d",s.retainCount);
    
    [s release];
    NSLog(@"reatinCount = %d",s.retainCount);
    */
    //属性的内存管理
    Teacher *t = [[Teacher alloc]init];
    Teacher *t2 = [[Teacher alloc]init];

    Student *stu = [[Student alloc]init];
    stu.teacher = t;
    stu.teacher = t2;
    
    
    [t release];
    [t2 release];
    
    //sleep(10);//让系统休眠10秒
    
    [stu.teacher onClass];
    [stu release];
/*
    Student *s1 = [[Student alloc]init];
    Student *s2 = s1;
    NSLog(@"s2 = %d",s2.retainCount);
    [s2 retain];//2
    NSLog(@"s1 = %d",s1.retainCount);
    NSLog(@"s2 = %d",s2.retainCount);
    [s1 release];
    NSLog(@"s1 = %d",s1.retainCount);
    NSLog(@"s2 = %d",s2.retainCount);
*/

 


 

属性与构造器手动内存写法

AInstance.h

#import <Foundation/Foundation.h>

@interface AInstance : NSObject
{
    NSString *_name;
    int _age;
    int _cityCode;
}

-(void)setName:(NSString *)aName;
-(NSString *)name;

-(void)setAge:(int)aAge;
-(int)age;

-(void)setCityCode:(int)aCityCode;
-(int)cityCode;

-(AInstance *)initWithName:(NSString *)aName
             andAge:(int)aAge
        andCityCode:(int)aCityCode;

+(AInstance *)aInstanceWithName:(NSString *)aName
                  andAge:(int)aAge
             andCityCode:(int)aCityCode;

@end

AInstance.m

#import "AInstance.h"
@implementation AInstance
-(void)setName:(NSString *)aName
{
    if (_name != aName)
    {
        [_name release];
        _name = [aName retain];
    }
}
-(NSString *)name
{
    return _name;
}

-(void)setAge:(int)aAge
{
    _age = aAge;
}
-(int)age
{
    return _age;
}

-(void)setCityCode:(int)aCityCode
{
    _cityCode = aCityCode;
}
-(int)cityCode
{
    return _cityCode;
}

-(AInstance *)initWithName:(NSString *)aName
             andAge:(int)aAge
        andCityCode:(int)aCityCode
{
    self = [super init];
    if (self)
    {
        _name = aName;
        _age = aAge;
        _cityCode = aCityCode;
    }
    return self;
}

+(AInstance *)aInstanceWithName:(NSString *)aName
                  andAge:(int)aAge
             andCityCode:(int)aCityCode
{
    AInstance *ainstance = [[AInstance alloc]initWithName:aName
                                                   andAge:aAge
                                              andCityCode:aCityCode];
    return [ainstance autorelease];
}


- (void)dealloc
{
    [_name release];
    
    [super dealloc];
}
@end

AppDelegate.m

AInstance *a = [[AInstance alloc ]initWithName:@"jobs"
                                           andAge:19
                                      andCityCode:20];
    NSLog(@"%@",a.name);
    [a release];  

2.

NSAutoreleasePool

/*任何OC对象只要调用autorelease方法,就会把该对象放到离自己最近的自动释放池中(栈顶的释放池)*/
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
    for (int i = 0; i < 1000000; i++)
    {
        NSMutableString *str = [[NSMutableString  alloc]init];
        [str autorelease];
        if (i%1000 == 0)
        {
            [pool release];/*该程序每执行1000次,就把池子销毁,
                            也就是str在自动释放池累积的对象不会超过1000个*/
            
            pool = [[NSAutoreleasePool alloc]init];//同时新建一个池子
        }
    }
    [pool release];

 

 

 

 

posted @ 2014-01-15 17:47  forrHuen  阅读(265)  评论(0编辑  收藏  举报