NSMutableArray 内存释放分析

在关闭ARC情况下对NSMutableArray存储内存分析。

一:测试环境构建

1:创建一个简单视窗工程 在AppDelegate.m

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
    // Override point for customization after application launch.
    ViewController *viewCtrl =[[[ViewController alloc] initWithNibName:@"ViewController" bundle:nil] autorelease];
    UINavigationController *navigationCtrl = [[UINavigationController alloc] initWithRootViewController:(UIViewController*) viewCtrl];
    self.viewController =  (ViewController*)navigationCtrl;
    self.window.rootViewController = self.viewController;
    [navigationCtrl release];
    [self.window makeKeyAndVisible];
    return YES;
}

 

2 在ViewController.m中

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    UIBarButtonItem *rightItm = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:@selector(rightTarget:)];
    self.navigationItem.rightBarButtonItem = rightItm;
    
    UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:@"根视图" style:UIBarButtonItemStyleDone target:nil action:nil];
    self.navigationItem.backBarButtonItem = backButton;
    [backButton release];
    
    [rightItm release];
}

-(void)rightTarget:(id)sender
{
    SecondViewController *secondViewCtrl = [[SecondViewController alloc] init];
    [self.navigationController pushViewController:secondViewCtrl animated:YES];
    [secondViewCtrl release];
}

3在 SecondViewController.h中申明如下:

 NSMutableArray *arrayObj;

 SecondViewController.m中实现

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self)
    {
        // Custom initialization
        [self.view setBackgroundColor: [UIColor grayColor] ];
        [self initArrayData];
    }
    return self;
}
-(void)initArrayData
{
    arrayObj = [[NSMutableArray alloc] initWithCapacity:0];
    DataSorceViewController *dataViewCtrl = nil;
    for (int i = 0 ; i < 1024; i++)
    {
        dataViewCtrl = [[DataSorceViewController alloc] init];
        [arrayObj addObject: dataViewCtrl];
    }
    
}
-(void)viewWillDisappear:(BOOL)animated
{
    
    
    for ( DataSorceViewController *data in arrayObj)
    {
        [data release];
        data = nil;
    }
     
    [arrayObj removeAllObjects];
    [arrayObj release];
    arrayObj = nil;
}

4 引入测试用的数据对象 DataSorceViewController,这里用的UIViewController子类,可以用任何类型的数据做为测试

 

二 :测试操作

1,SecondViewController.m 的  -(void)viewWillDisappear:(BOOL)animated 中不做任何操作。用profile memeory leak测试,当页面切换操作后发现,有红色标注,表示有内存泄漏。

2. -(void)viewWillDisappear:(BOOL)animated函数中加入 

 [arrayObj release];

 arrayObj = nil;

 

切换页面,profile memeory leak中没有发现有红色标注,表示没有内存泄漏吗?其实不然,在Statistics的数据对象列表中,DataSorceViewController 对象始终存在,而且在多次切换操作中DataSorceViewController对象所占的内存每切换一次就会增长一次。多次切换后内存DataSorceViewController对象占用内存居高不下。

3:-(void)viewWillDisappear:(BOOL)animated函数中加入

[arrayObj removeAllObjects];
[arrayObj release];
arrayObj = nil;

效果同第二步。

4:增加对数组对象释放操作

for ( DataSorceViewController *data in arrayObj)
    {
        [data release];
        data = nil;
    }
     
    [arrayObj removeAllObjects];
    [arrayObj release];
    arrayObj = nil;

在页面每次切换以后,DataSorceViewController 对象被释放。

 

结论:

一:profile memeory leak 检测,那个红色的标示并不是可靠的,即使有内存泄漏,leaks红色标示也可能没有出现

二:NSArray(NSMutableArray)数组,在 addObject 操作是会对对象做retain操作,同时 removeobject 操作会对对象做release操作,但数组中保存的对象所占的内存并没有释放,因为alloc操作时候retaincount 为1,一次addObject操作,retaincount 2,rimoveObject操作,retaincont为1,实际内存并没有得到释放。要真正释放内存,要遍历数组,对数组中保持的每个对象做release操作。 最后清除数组所有对象以及其本身。同理可得其它容器也是相同性质,比如NSDictionary等

三:以上为个人试验结论,如有不正确地方,欢迎指正!

posted @ 2013-05-21 17:25  酱酱爱  阅读(4483)  评论(0编辑  收藏  举报