ARC下的内存泄露

iOS提供了ARC功能,很大程度上简化了内存管理的代码。java

但使用ARC并不表明了不会发生内存泄露,使用不当照样会发生内存泄露。objective-c

下面列举两种ARC致使内存泄露的状况。app

1,循环参照ide

A有个属性参照B,B有个属性参照A,若是都是strong参照的话,两个对象都没法释放。函数

这种问题常发生于把delegate声明为strong属性了。动画

例,atom

@interface SampleViewControllerspa

@property (nonatomic, strong) SampleClass *sampleClass;指针

@end调试

@interface SampleClass

@property (nonatomic, strong) SampleViewController *delegate;

@end

 

上例中,解决办法是把SampleClass 的delegate属性的strong改成assing便可。

 

 

2,死循环

若是某个ViewController中有无限循环,也会致使即便ViewController对应的view关掉了,ViewController也不能被释放。

这种问题常发生于animation处理。

例,

好比,

CATransition *transition = [CATransition animation];

transition.duration = 0.5;

tansition.repeatCount = HUGE_VALL;

[self.view.layer addAnimation:transition forKey:"myAnimation"];

 

上例中,animation重复次数设成HUGE_VALL,一个很大的数值,基本上等于无限循环了。

解决办法是,在ViewController关掉的时候,中止这个animation。

-(void)viewWillDisappear:(BOOL)animated {

    [self.view.layer removeAllAnimations];

}

 

内存泄露的状况固然不止以上两种。

即便用了ARC,咱们也要深入理解iOS的内存管理机制,这样才能有效避免内存泄露。

 

arc的程序出现内存泄露怎办

实例一:

用arc和非arc混编,非arc的类在arc里实例化而且使用,在arc里竟然出现内存泄露,并且应为是arc,因此没法使用release,autorelease和dealloc去管理内存。正常状况下应该是不会出现这种状况的,某一个类如果ARC,则在这个类里面都应该遵循ARC的用法,而无需关心用到的类是不是ARC的,一样,在非ARC类里面,就须要遵循内存管理原则。


用ARC,只是编译器帮你管理了什么时候去release,retain,不用ARC就须要你本身去管理,说到底只是谁去管理的问题,因此你再好好看看,可能问题与ARC无关。
若是实在找不到问题,建议你找到泄露的那个对象,将其赋值为nil,由于ARC里面,一旦对象没有指针指向,就会立刻被释放。
 

实例二:

最近在学objective-c,我发现建立项目时若是使用了ARC,很是容易内存泄露,常常某个对象已经被释放掉了我还在使用,因为不太了解这个机制,如今我举出两个例子,请经验者帮我分析一下。
例子一:一开始,在AppDelegate.m的那个开始方法中时这样写的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
     self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];    
     // Override point for customization after application launch.
     self.window.backgroundColor = [UIColor whiteColor];
     //
     UITabBarController  tabBarController = [[UITabBarController alloc] init];
     [tabBarController setViewControllers:[self showConnectViewOnWindow]];
     [tabBarController setDelegate:self];
     //
     [[self window] addSubview: [tabBarController view]];
     
     [self.window makeKeyAndVisible];
     return  YES;
}

而后,我还作了其余的工做:tabBarController中有tabBarItem,点击会调用一个方法
可是每次一点击,就会报unrecognized selector send to instance的错误,
后来上网一查,说是要把tabBarController定义成全局变量,否则这个方法一结束,tabBarController就被释放掉了,这样点击产生时间的对象都没了,因而我把它定义成全局变量,确实能够了,但个人疑问是,为何方法一结束他就会释放掉吗,[[self window] addSubview: [tabBarController view]];我这一句不是已经在self window里引用它了吗,他怎么还会被释放,我以为java和C#里面这种状况是不会释放掉了。

1
2
3
4
5
6
7
8
例子二:在viewdidload方法里面:
     [self.navigationItem setTitle:Title];
     
     leftButton = [[UIBarButtonItem alloc] initWithTitle:Cancel 
                                                   style:UIBarButtonItemStyleBordered 
                                                  target:self 
                                                  action: @selector (CancleButtonClicked)];
     self.navigationItem.leftBarButtonItem = leftButton;

这里我给屏幕上方那个导航条加了一个左边的按钮,而后点击这个按钮后会用方法CancleButtonClicked来响应,可是我运行起来一点击,仍是报unrecognized selector send to instances错误了,这里又是哪一个对象释放了,leftButton吗?可是self.navigationItem.leftBarButtonItem = leftButton已经引用了啊。

 

解决方法:

 

例子一[[self window] addSubview: [tabBarController view]];
你只引用了tabBarController的view,没有引用tabBarController

例子二,不知道什么缘由,看看有没有拼写错误吧。

另外,我感受局部变量的内存通常只在它的生命周期内有效。出了它所定义的区域,即便不释放,也最好不要用了。

 

 

自从使用了ARC,代码写起来方便了不少,不须要retain,release,dealloc了,可是也隐藏了一些释放内存的问题。

若是你不打印一下dealloc中的信息,也许你还真的不知道你的controller,view等等资源没有释放。不少问题均可能形成资源不可以及时释放。其中有一个很容易忽略的问题,block会自动retain你的变量。
若是你引用的是一个实例变量,它会直接对 self进行 retain,这有时候有可能会产生一个引用环(两个或以上的对象之间直接或间接地互相引用)并致使内存泄露。解决的方法是:当须要在 Block中访问实例变量的时候,建立一个指向 self的指针,并对其使用 __block修饰符,这样 self不会被自动 retain
 
 
说法二
 

BLock的内存泄露

  在咱们代码中关于block的使用能够说随处可见,第一次接触block的时候是关于UIView的块动画,那时以为block的使用好神奇, 再后来分析总结为block其实就是一个c语言函数,只是咱们能够在任意处调用此函数。有了这样的理解我开始常用block。在作项目之后发现使用 block居然会引发内存泄露,因而开始本身调试研究block的内存管理问题。

普通的block使用(包括块动画)

这里有一个简单的block使用,在里面咱们能够添加任何本身想进行的操做,大部分的使用也是如此

1 void (^Block)(int) = ^(int num){
2    //此处还可添加其余代码 ....
3    NSLog(@"int number is %d",num);
4 };

包括UIView的块动画也是如此使用,在这里咱们定义了一个图像视图的位置及透明度的变化

1 [UIView animateWithDuration:2.0 animations:^(void){
2     smallImage.frame = CGRectMake(150, 80, 30, 30);
3 } completion:^(BOOL finished) {
4      smallImage.alpha = 0;

这些block操做中,我一直都认为block中的对象会在block使用后就被释放(但UIView的操做好像是这么作的)

block内存管理初现

  直到我在项目中碰见这样一个状况:我设置有2个控制器first及second,其中second中包含一个block对象,而block的实 现是在first中实现(通常的block传值都是这么作)。而界面的推送是由first控制器push出second控制器。但当我second控制器 pop的时候,问题出现second控制器不走delloc方法,即pop后second控制器还存在没有被销毁(由于当时要作delloc中作一些操 做,才发现这个问题)!block示例代码以下:

first控制器中block的实现

1 SecondViewController *secondVC = [[SecondViewController alloc] init];
2 secondVC .block = ^(NSString *text){
3         self.text = secondVC.text;
4 };

  这么一个简单的传值block使用,竟然能引发second控制器没法释放,因而研究其原理,并网上搜索资料,得出一个结论:second控制 器在block中被持有一次才致使其没法释放。由于block本质上是一个函数,而编译器不知道你何时会调用block里面的值,因此为了确保编译器 内secondVC不会被释放,编译器会自动对其进行一次持有(在自身类中使用block方法操做自身的成员属性也会使本身的引用计算加1,形成没法释 放)。

其解决办法也简单 在外部添加一个弱引用对象指向须要在block中操做的对象,即__weak typeof(对象名) 别名= 对象名;

1 SecondViewController *secondVC = [[SecondViewController alloc] init];
2 __weak typeof(secondVC) second = secondVC;
3 __weak typeof(self) vc = self;
4 2 secondVC .block = ^(NSString *text){
5 3         vc.text = second.text;
6 4 };

这样就可以有效的防止block使用引发的内存泄露问题。

NSTimer使用问题

另外在还在项目中碰见一个关于NSTimer的使用问题。咱们想到在控制器销毁时同时中止NSTimer并置为nil

1 -(void)dealloc {
2     [self.timer invalidate];
3     self.timer = nil;
4     NSLog(@"%@ dealloc", NSStringFromClass([self class]));
5 }

然而控制器被pop后并无走此方法(又是内存泄露),因为以前出现了Block内存泄露的问题,我就想是否是由于这个_timer加载的时候对self进行了一次持有

_timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerUp:) userInfo:nil repeats:YES];

进行调试测验,果真是这里出了问题,由于其对控制器持有了一次。因而我想到既然这样那我干脆就在viewWillDisappear()中作个判 断,若是是pop控制器,我就先设置[self.timer invalidate]操做这样控制器就会走dealloc()方法。后来再网上找资料发现了一个更简单的解决办法,即同Block的内存管理同样使用弱 引用对象

1 __weak typeof(self) vc = self;
2 _timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:vc selector:@selector(timerUp:) userInfo:nil repeats:YES];

这样的解决办法就要比我以前的要简单多了,惟一须要注意的就是此处vc的做用域!

相关文章
相关标签/搜索