iPhone中管理malloc分配的内存空间

Posted on 2012-03-11 03:03  无忧consume  阅读(206)  评论(0编辑  收藏  举报

  我们都知道在C/C++语言中,堆内存是应该由程序员负责释放的,编译器并不负责释放程序员自己分配的堆内存空间;而在Objective-C语言 中,类实例的释放是通过release方法进行释放的,如果是Autorelease Pool中的实例,程序员还不必自己手动释放相应的内存空间,这点对于习惯在iPhone中使用C/C++风格编写程序的程序员来说,无疑是有点迷惑性 的,例如下面的代码: 

view plaincopy to clipboardprint? 

  1. #import <Foundation/Foundation.h>  
  2.   
  3.   
  4. @interface MemoryManager : NSObject {  
  5. @public  
  6.         char* memory;  
  7. }  
  8.   
  9. @end  

 

 

 

view plaincopy to clipboardprint?

 

  1. #import "MemoryManager.h"  
  2.   
  3.   
  4. @implementation MemoryManager  
  5. -(id) init  
  6. {  
  7.         if (self = [super init])  
  8.         {  
  9.         }  
  10.           
  11.         return self;  
  12. }  
  13.   
  14. - (void)dealloc  
  15. {  
  16.         NSLog(@"dealloc MemoryManager");  
  17. }  
  18. @end   


      笔者在MemoryManager中声明了一个char*的变量,并且这个变量的访问权限是公开的(@public属性),那么如果在别的类中显示的为 char*分配了内存空间,这些空间应该交给谁负责释放?是应该由程序员自己调用free函数进行释放,还是应该由实例调用release方法进行释放?
代码如下:

 

view plaincopy to clipboardprint?

 

  1. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {      
  2.       
  3.     // Override point for customization after application launch.  
  4.     MemoryManager* manager = [[MemoryManager alloc] init];  
  5.     manager->memory = (char*)malloc(5);  
  6.     NSLog(@"memory address :%x",(manager->memory));  
  7.     memcpy(manager->memory,"abcd",4);  
  8.     [manager release];  
  9.     [self.window makeKeyAndVisible];  
  10.       
  11.     return YES;  
  12. }  

 

      很明显,如果在上面的代码中调用了free(manager->memory)来显示的释放内存,如果后面的代码还在使用这块内存空间,无疑会造成内存管理的混乱,如下代码: 

 

view plaincopy to clipboardprint?

 

  1. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {      
  2.       
  3.     // Override point for customization after application launch.  
  4.     MemoryManager* manager = [[MemoryManager alloc] init];  
  5.     manager->memory = (char*)malloc(5);  
  6.     NSLog(@"memory address :%x",(manager->memory));  
  7.     memcpy(manager->memory,"abcd",4);  
  8.       
  9.     NSMutableArray* tempArray = [[NSMutableArray alloc] initWithCapacity:10];  
  10.     [tempArray addObject:manager];  
  11.     free(manager->memory);  
  12.       
  13.     [manager release];  
  14.     [self.window makeKeyAndVisible];  
  15.       
  16.     return YES;  
  17. }  

 

       在上面的代码中,笔者把manager实例添加到一个NSMutableArray实例中,然后释放了manager->memory所引用的内存 空间,但是tempArray实例在以后的代码中可能还会使用manager->memory进行内存访问,那么程序无疑会发生crash;所以我 们需要保证manager->memory的生命周期和它所处的实例的生命周期一致,这样无论任何时候通过manager->memory访 问内存空间都会得到正确的结果,我们知道C++中是通过析构函数来保证这点的,通过调用delete,那么编译器会调用相应对象的析构函数进行对象内部堆 空间的释放。

      其实在iPhone中,release的作用和delete是一样的,它会调用对象的dealloc方法,唯一不同的是release是基于引用计数的, 在调用release方法的时候,只有引用内存空间的计数为0时才会调用实例的release方法进行内存释放,由于[tempArray addObject:manager]对manager进行了retain操作,所以manager实例的引用计数为2,在tempArray使用完 manager对象后,通过调用release方法就可以释放manager对象及其内部的memory指针所引用的内存堆空间。

于是很显然的是,程序员需要在dealloc方法中管理类对象的内存指针以及相应的内存空间,合理的代码如下:

 

view plaincopy to clipboardprint?

 

  1. #import "MemoryManager.h"  
  2.   
  3.   
  4. @implementation MemoryManager  
  5. -(id) init  
  6. {  
  7.         if (self = [super init])  
  8.         {  
  9.         }  
  10.           
  11.         return self;  
  12. }  
  13.   
  14. - (void)dealloc  
  15. {  
  16.         NSLog(@"dealloc MemoryManager");  
  17.         free(memory);  
  18. }  
  19. @end  

 

      这样无论程序员在什么时候使用MemoryManager来产生对象,那么只需要记住释放相应的对象,而这个对象内部memory指针所引用的内存空间也相应的被释放了,这无疑是很好的编程习惯!

  测试代码下载地址:http://www.pocketcn.com/forum.php?mod=viewthread&tid=426&page=1&extra=#pid3098

Copyright © 2024 无忧consume
Powered by .NET 8.0 on Kubernetes