OC 手动内存管理

一.了解内存管理

iphone 会对程序占用内存设置阀值,当达到第一和第二阀值的时候,会进行警告,如果已经达到第三阀值时,则OS会直接kill.

内存管理的目的:就是将不参与逻辑的对象,清除出内存,把空间给需要参加逻辑的对象

1.严格的内存管理让程序的性能得到提高

2.如果忽视内存管理,将导致程序占用内存过高,进而导致程序崩溃

注意:2012年的之前的项目很多都是手动内存管理,没有ARC,IOS5后都是ARC机制。



二.手动内存管理

如果是Xcode4.0以上的版本,Xcode以上的版本模式内存管理是ARC,手动内存需要对编译器做以下设置 :

工程目录--> Buid Settings --> Objective-C Automatic Reference Count  --> 修改为NO。


在对象中,有个retainCount属性,是该对象的引用计数器值,如果等于0,则表示对象已经没有引用,就会调用dealloc方法进行摧毁死亡。对象的属性和方法将不能被调用。但可以人为的干预retainCount的值。

1) 使用alloc、new或者copy创建一个新对象时,新对象的引用计数器默认为1

2) 调用对象retain方法,会让引用计数器值+1(retain方法id指针)

3) 调用对象release方法,会让引用计数器值-1

4) 通过对象retainCount方法,获得当前的引用计数器值

5) 当retainCount=0时,对象就认为要摧毁,会自动调用dealloc 函数通知对象即将死亡。及时性。



三.内存管理的准则

只要出现了new alloc retain 就必须配对出现严格release 或者 autorelease; 如果没有按照这种规则来写,则会有内存泄露的风险。

1) 谁创建,谁release

    如果你通过alloc、new或[mutable]copy来创建一个对象,那么你必须调用release或autorelease

2) 谁retain,谁release

    只要你调用了retain,无论这个对象是如何生成的,你都要调用release



四.内存管理的其他概念

内存溢出:对象使用完毕,但是并没有移除内存。retainCount 不为0

野指针:指向释放掉的对象的指针,为了防止野指针,将使用完毕的对象赋值为nil    

僵尸对象:retainCount 为0 的就是僵尸对象,代表不能正确访问的对象



五.相关OC异常

EXC_BAD_ ACCESS DA 代表访问了一块被释放掉的内存,野指针



六.代码

Car Engine类,Car类是Engine类的父类,他们具有组合关系,Car拥有Engine

1.Car类

===Car类声明===
@interface Car : NSObject
@property (nonatomic,strong)Engine *engine;

-(void)setEngine:(Engine *)engine;
@end


===Car类实现===
@implementation Car
- (void)dealloc
{
    [_engine release];
    NSLog(@"%@ dealloc...",self.className);
    [super dealloc];   
}

//重写set方法
-(void)setEngine:(Engine *)engine
{
    
    
    
    //第一次重写
    /*
     重写代码:
     _engine=engine;
     
     
     调用代码分析
     
     Car *car = [[Car alloc]init];
     Engine *engine = [[Engine alloc]initWithMode:@"byd"];
     [car setEngine:engine];
     该步骤是Car的 _engine 成员变量指向 engine对象,也就是引用数+1。
     但是setEngine 方法中的 _engine=engine 并未让retainCount+1.
     
     [engine release];//这步 engine 释放。
     [car release];
     
     */
    
    
    
    
    
    //第二次改进
    /*
     重写代码:
     _engine=[engine retain];
     
     
     调用代码分析:
     Car *car = [[Car alloc]init];
     Engine *engine1 = [[Engine alloc]initWithMode:@"byd"];
     [car setEngine:engine1];//设置的时候,又有另外一个指针指向engine
     NSLog(@"engine1=%p",engine1);
     
     //更换引擎
     Engine *engine2 = [[Engine alloc]initWithMode:@"byd"];
     [car setEngine:engine2];//_engine 指向 engine2
     NSLog(@"engine2=%p",engine2);
     
     
     [engine1 release];
     [engine2 release];
     [car release];
     
     输出结果
     014-10-22 23:16:16.613 08-内存管理1[1586:303] engine1=0x1001034c0
     2014-10-22 23:16:16.615 08-内存管理1[1586:303] engine2=0x10010cf30
     2014-10-22 23:16:16.615 08-内存管理1[1586:303] 0x10010cf30 dealloc...
     2014-10-22 23:16:16.615 08-内存管理1[1586:303] Car dealloc...
     
     可以看出engine1并没有被释放,照成了内存溢出。并且程序也不符合原理,在engine2赋值给car时,engine1引用值-1;
     
     */
    
    

    
    
    
    //第三次改进
    /*
    改进后的代码:
     [_engine release];
    _engine=[engine retain];
     
     
    该代码已经解决了上面的问题。
     
     代码分析:
     Car *car = [[Car alloc]init];
     Engine *engine1 = [[Engine alloc]initWithMode:@"byd"];
     [car setEngine:engine1];//这步_engine = engine1; engine1 的 retainCount=2;
     NSLog(@"engine1=%p",engine1);
     
     //更换引擎
     Engine *engine2 = [[Engine alloc]initWithMode:@"byd"];
     [car setEngine:engine2];//这步 先让engine1 引用数-1,让后把engine2的引用数+1,并且赋给_engine
     NSLog(@"engine2=%p",engine2);
     
     
     [engine1 release];//engine1被摧毁
     [engine2 release];//这步 engine2 retainCount= 1
     [car release];//cat 被摧毁 调用dealloc方法,摧毁 engine2 和 car对象
     
     
     输出:
     2014-10-22 23:24:46.037 08-内存管理1[1605:303] engine1=0x1002005c0
     2014-10-22 23:24:46.039 08-内存管理1[1605:303] engine2=0x100403840
     2014-10-22 23:24:46.039 08-内存管理1[1605:303] 0x1002005c0 dealloc...
     2014-10-22 23:24:46.039 08-内存管理1[1605:303] 0x100403840 dealloc...
     2014-10-22 23:24:46.040 08-内存管理1[1605:303] Car dealloc...
     
     
    */
    
    
    
    
    //最终代码
    if (_engine != engine) {//避免重复调用,如果重复调用,先把引用数-1,再+1,没有意义
        [_engine release];
        _engine=[engine retain];
    }
}
@end


2.Engine类

===类声明===
@interface Engine : NSObject
@property (nonatomic,copy)NSString *mode;
- (instancetype)initWithMode:(NSString *) mode;
@end


===类实现===
@implementation Engine

- (void)dealloc
{
    NSLog(@"%p dealloc...",self);
    [super dealloc];
}


- (instancetype)initWithMode:(NSString *) mode
{
    self = [super init];
    if (self) {
        [self setMode:mode];
    }
    return self;
}

@end


3.主函数

int main(int argc, const char * argv[])
{

    Car *car = [[Car alloc]init];
    Engine *engine1 = [[Engine alloc]initWithMode:@"byd"];
    [car setEngine:engine1];//设置的时候,又有另外一个指针指向engine
    NSLog(@"engine1=%p",engine1);
    
    //更换引擎
    Engine *engine2 = [[Engine alloc]initWithMode:@"byd"];
    [car setEngine:engine2];//_engine 指向 engine2
    NSLog(@"engine2=%p",engine2);
    
    
    [engine1 release];
    [engine2 release];
    [car release];
    
    return 0;
}


输出
2014-10-23 00:12:34.840 08-内存管理1[1812:303] engine1=0x1002005c0
2014-10-23 00:12:34.841 08-内存管理1[1812:303] engine2=0x100100370
2014-10-23 00:12:34.841 08-内存管理1[1812:303] 0x1002005c0 dealloc...
2014-10-23 00:12:34.842 08-内存管理1[1812:303] 0x100100370 dealloc...
2014-10-23 00:12:34.842 08-内存管理1[1812:303] Car dealloc...


你可能感兴趣的:(OC 手动内存管理)