iOS 記憶體洩漏的常見場景

2021-08-22 14:46:24 字數 3127 閱讀 5154

注意以create,copy作為關鍵字的函式都是需要釋放記憶體的,注意配對使用。比如:cgcolorcreate<-->cgcolorrelease

這部分不做詳細介紹,也是注意配對使用,需要說明的是,如果**中有部分檔案是mrc的,在已有檔案中加**的時候注意一下,不能都按照arc的方式處理。

arc已經為我們做了很多封裝,我們不必再顯示的呼叫retain,release,但是還是要注意迴圈引用的場景。

在此,常規的物件間的互相引用和block的迴圈引用大家都比較了解,這裡就不贅述了,羅列幾個我們**中的錯誤。

1. nstimer

nstimer會造成迴圈引用,timer會強引用target即self,一般self又會持有timer作為屬性,這樣就造成了迴圈引用。

那麼,如果timer只作為區域性變數,不把timer作為屬性呢?同樣釋放不了,因為在加入runloop的操作中,timer被強引用。而timer作為區域性變數,是無法執行invalidate的,所以在timer被invalidate之前,self也就不會被釋放。

所以我們要注意,不僅僅是把timer當作例項變數的時候會造成迴圈引用,只要申請了timer,加入了runloop,並且target是self,雖然不是迴圈引用,但是self卻沒有釋放的時機。如下方式申請的定時器,self已經無法釋放了。

nstimer *timer = [nstimer timerwithtimeinterval:5 target:self selector:@selector(commentanimation) userinfo:nil repeats:yes];

[[nsrunloop currentrunloop] addtimer:timer formode:nsrunloopcommonmodes];

每次任務結束時使用dispatch_after方法做延時操作。注意使用weakself,否則也會強引用self。

- (void)startanimation

);}

ws(weakself);

timer = dispatch_source_create(dispatch_source_type_timer, 0, 0, dispatch_get_main_queue());

dispatch_source_set_timer(timer, dispatch_time_now, 5 * nsec_per_sec, 1 * nsec_per_sec);

dispatch_source_set_event_handler(timer, ^);

dispatch_resume(timer);

2. nsnotification

使用block的方式增加notification,引用了self,在刪除notification之前,self不會被釋放,與timer的場景類似,其實這段**已經宣告了weakself,但是呼叫_eventmanger方法還是引起了迴圈引用。

也就是說,即使我們沒有呼叫self方法,_***也會造成迴圈引用。

[[nsnotificationcenter defaultcenter] addobserverforname:kusersubscribenotification object:nil queue:nil usingblock:^(nsnotification *note) 

}}

3. __block

__blockmrc中是不會增加引用的,可是在arc中會增加,所以在arc中,只能使用__weak去打破迴圈引用。

__block myviewcontroller *weaksef = self;

_myviewcontroller.editblock = ^();

另外宣告一點,並非所有的block都需要使用weak來打破迴圈引用,如果self沒有持有block就不會造成迴圈引用(例如, 動畫block塊)。而有些地方之所以使用了__weak,是為了在[self dealloc]之後就不再執行了。在這種場景下使用weakself時,也需要注意,如果self被釋放了會不會引起異常。比如下面這段**把weakself取到的值作為入參,如果self釋放了,傳nil,引起crash:

[[httpcore sharedinstance] getrequestwithpath:url target:self params:params success:^(nsdictionary *result, nsurlrequest *request, nshttpurlresponse *response)  failure:^(nserror *error) ];
4.performselector記憶體洩露

performselector延時呼叫的問題,

performselector關於記憶體管理的執行原理是這樣的:執行 [self performselector:@selector(method1:) withobject:self afterdelay:3]; 的時候,系統會將self的引用計數加1,執行完這個方法時,還會將self的引用計數減1,當方法還沒有執行的時候,要返回父檢視釋放當前檢視的時候,self的計數沒有減少到0,而導致無法呼叫dealloc方法,出現了記憶體洩露。

所以最後我的解決辦法就是取消那些還沒有來得及執行的延時函式,**很簡單:

[nsobject cancelpreviousperformrequestswithtarget:self]

當然你也可以乙個乙個得這樣用:

[nsobject cancelpreviousperformrequestswithtarget:self selector:@selector(method1:) object:nil]

加上了這個以後,dealloc方法就會被呼叫,問題解決!

為了安全還是

1.呼叫performa之前先單個取消一下  

2.彈出viewcontroller單個取消一下

3. 還有 一些特殊情況業務操作需要過幾秒,是不要取消,比如要儲存一些資料。

iOS 記憶體洩漏的常見場景

注意以creat,copy作為關鍵字的函式都是需要釋放記憶體的,注意配對使用。比如 cgcolorcreate cgcolorrelease 這部分不做詳細介紹,也是注意配對使用,需要說明的是,如果 中有部分檔案是mrc的,在已有檔案中加 的時候注意一下,不能都按照arc的方式處理。arc已經為我們...

Golang 記憶體洩漏場景

雖然golang 的runtime 會 記憶體,但是本文列舉的場景仍然會造成記憶體洩漏。todo 此處需要了解下golang 的底層 memory block 分配知識 var s0 string 包級別變數 a demo purpose function.func f s1 string func...

常見的記憶體洩漏

vector v new vector 10 for int i 1 i 100 i 如果我們僅僅釋放引用本身,那麼 vector 仍然引用該物件,所以這個物件對 gc 來說是不可 的。因此,如果物件加入到vector 後,還必須從 vector 中刪除,最簡單的方法就是將 vector 物件設定為...