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等
三:以上为个人试验结论,如有不正确地方,欢迎指正!