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的做用域!

相關文章
相關標籤/搜索