Chinaunix首页 | 论坛 | 博客
  • 博客访问: 50634
  • 博文数量: 34
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 297
  • 用 户 组: 普通用户
  • 注册时间: 2014-04-09 10:52
文章分类

全部博文(34)

文章存档

2015年(23)

2014年(11)

我的朋友

分类: iOS平台

2015-04-09 17:11:43

一.内存管理

对基本数据类型无效,只对任何继承了NSObject的对象有效
 

每个对象内部都保存有整数,这个整数称之为引用计数器

当一个对象的引用计数器值为0的话,它将被销毁,占用的内存被系统回收,

OC会自动向对象发送dealloc消息,一定不要直接调用dealloc方法。

一般会重写dealloc方法,在里面释放相关资源。


当使用 alloc new  copy 创建一个对象时,对象的引用计数器为1,该对象会一直存在内存中,除非用户关闭应用。

给对象发消息,就是调用对象方法
给对象发送retain消息,引用计数器+1

给对象发送release消息,引用计数器-1
给对象发送retainCount可以获得当前对象的引用计数器值

内存管理法则

谁创建,谁释放

谁retain 谁release

在哪个方法里创建,就在哪个方法里释放

下面看一下内存管理的一段代码:
//  Student.m

点击(此处)折叠或打开

  1. #import "Student.h"

  2. @implementation Student

  3. @synthesize age = _age;

  4. -(void)dealloc{
  5.     
  6.     NSLog(@"%@销毁了",self);
  7.     
  8.     [super dealloc];//一定要调用super dealloc,最好放到最后面
  9. }

  10. @end

//  main.m

点击(此处)折叠或打开

  1. #import <Foundation/Foundation.h>
  2. #import "Student.h"

  3. int main(int argc, const char * argv[]) {
  4.     @autoreleasepool {
  5.         
  6.         Student *stu = [[Student alloc] init];
  7.         Student *stu1 = [[[Student alloc] init] autorelease];//在适当的时候,自动进行内存释放
  8.         
  9.          NSLog(@"size--%zd",[stu retainCount]);
  10.         
  11.         [stu retain];
  12.         
  13.          NSLog(@"size--%zd",[stu retainCount]);
  14.         
  15.         [stu release];
  16.         
  17.          NSLog(@"size--%zd",[stu retainCount]);
  18.         
  19.         [stu release];
  20.         
  21.         //[stu release];//会导致野指针错误,内存已经被释放,指针还去访问他。
  22.         
  23.     }
  24.     return 0;

  25. }

运行结果:

2015-04-09 15:26:41.312 内存管理-1[9838:303] size--1

2015-04-09 15:26:41.314 内存管理-1[9838:303] size--2

2015-04-09 15:26:41.314 内存管理-1[9838:303] size--1

2015-04-09 15:26:41.315 内存管理-1[9838:303] 销毁了

2015-04-09 15:26:41.315 内存管理-1[9838:303] 销毁了



二.对象之间的内存管理

看下面的代码,会导致野指针错误:
//  Student.m

点击(此处)折叠或打开

  1. #import "Student.h"

  2. @implementation Student

  3. //@synthesize age = _age;

  4. -(void)dealloc{
  5.     
  6.     NSLog(@"age--%d--销毁了",_age);
  7.     
  8.     [super dealloc];
  9. }

  10. -(id)initWithAge:(int)age{

  11.     if((self = [super init]) != nil){
  12.     
  13.         _age = age;
  14.     
  15.     }
  16.     return self;
  17.     
  18. }

  19. -(void)readBook{
  20.     
  21.     
  22.     NSLog(@"读的书是:%f",_book.price);
  23.     
  24. }

  25. @end
//  main.m

点击(此处)折叠或打开

  1. #import <Foundation/Foundation.h>
  2. #import "Student.h"
  3. #import "Book.h"


  4. void test(Student *stu){

  5.    
  6.     Book *bo = [[Book alloc] initWithBook:9.9];
  7.     
  8.     stu.book = bo;
  9.     
  10.     [bo release];

  11. }

  12. void test1(Student *stu){

  13.     [stu readBook];//会引起野指针

  14. }

  15. int main(int argc, const char * argv[]) {
  16.     @autoreleasepool {
  17.         
  18.         Student *stu = [[Student alloc] initWithAge:39];
  19.         
  20.         //Book *bo = [[Book alloc] initWithBook:3.2];
  21.         
  22.         test(stu);
  23.         test1(stu);
  24.         
  25.         [stu release];
  26.         //[bo release];
  27.         
  28.     }
  29.     return 0;

  30. }

谁想使用对象,谁就retain

针对上述代码的改进,看下下面的代码:
//  Student.m

点击(此处)折叠或打开

  1. #import "Student.h"

  2. @implementation Student

  3. //@synthesize age = _age;

  4. -(void)dealloc{
  5.     
  6.     NSLog(@"age--%d--销毁了",_age);
  7.     
  8.     [_book dealloc];//释放student时候释放book
  9.     
  10.     [super dealloc];
  11. }

  12. -(id)initWithAge:(int)age{

  13.     if((self = [super init]) != nil){
  14.     
  15.         _age = age;
  16.     
  17.     }
  18.     return self;
  19.     
  20. }

  21. -(void)readBook{
  22.     
  23.     
  24.     NSLog(@"读的书是:%f",_book.price);
  25.     
  26. }

  27. -(void)setBook:(Book *)book{

  28.     _book = [book retain];//使用了就retain

  29. }

  30. -(Book *)book{

  31.     return _book;
  32. }


  33. @end
修改以下函数后,还是会出现内存泄露,如下:
因为set了两遍,所以retain了两遍,但是释放时候只release了一遍

点击(此处)折叠或打开

  1. void test(Student *stu){

  2.     Book *bo = [[Book alloc] initWithBook:9.9];
  3.     
  4.     stu.book = bo;
  5.     
  6.     [bo release];
  7.     
  8.     Book *bo1 = [[Book alloc] initWithBook:9.9];
  9.     
  10.     stu.book = bo1;
  11.     
  12.     [bo1 release];


  13. }

OC里面给一个空的对象发送消息是不会错的

//防止上述内存泄露,可以这样写

-(void)setBook:(Book *)book{


    //先释放就的成员变量,虽然有可能是nil

    [_book release];

    _book = [book retain];



}


点击(此处)折叠或打开

  1. void test(Student *stu){

  2.     Book *bo = [[Book alloc] initWithBook:19.9];
  3.     stu.book = bo;
  4.     
  5.     [bo release];
  6.     
  7.     stu.book = bo;//这里会引起野指针,因为重复调用了set方法
  8.     
  9.     Book *bo1 = [[Book alloc] initWithBook:9.9];
  10.     
  11.     stu.book = bo1;
  12.     
  13.     [bo1 release];


  14. }

[_book release];

[_book release];//这样是野指针,是不可以的

[nil release];//这样不是野指针,属于空指针,是可以的。


写成这样会避免上诉情况

-(void)setBook:(Book *)book{

    

    if(book != _book){

        //先释放就的成员变量

        [_book release];

        

        _book = [book retain];

    }



}


EXC_BAD_ACCESS 野指针错误






阅读(495) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~