日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關咨詢
選擇下列產(chǎn)品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
iOSobjc_msgSend尾調(diào)用優(yōu)化機制

本文基于Objective-C對象的消息傳遞機制,詳細分析OC對 objc_msgSend 的尾調(diào)用優(yōu)化方式。

成都創(chuàng)新互聯(lián)公司專注于企業(yè)成都全網(wǎng)營銷推廣、網(wǎng)站重做改版、撫遠網(wǎng)站定制設計、自適應品牌網(wǎng)站建設、HTML5、成都商城網(wǎng)站開發(fā)、集團公司官網(wǎng)建設、外貿(mào)網(wǎng)站建設、高端網(wǎng)站制作、響應式網(wǎng)頁設計等建站業(yè)務,價格優(yōu)惠性價比高,為撫遠等各大城市提供網(wǎng)站開發(fā)制作服務。

1. 什么是尾調(diào)用?

尾調(diào)用( TailCall):某個函數(shù)的***一步僅僅只是調(diào)用了一個函數(shù)(可以是自身,可以是另一個函數(shù))。 QiShare提醒:注意 “僅僅” 兩個字。

尾調(diào)用例子:

 
 
 
 
  1. // 尾調(diào)用: 
  2. - (NSInteger)funcA:(NSInteger)num {      
  3. /*  Some codes... */      
  4. if(num == 0) {        return [self funcA:num];// 尾調(diào)用->自身    }          
  5. if (num > 0) {        return [self funcB:num];// 尾調(diào)用->函數(shù)funcB    }          
  6. return [self funcC:num];// 尾調(diào)用->函數(shù)funcC} 

正例解釋:funcA 的***一步僅僅調(diào)用了另一個函數(shù)。不論是調(diào)用funcA、funcB還是funcC 都屬于尾調(diào)用。(不論調(diào)用函數(shù)的位置在哪,只要***一步僅僅調(diào)用一個函數(shù)就行。)

反例:不是尾調(diào)用的例子

 
 
 
 
  1. // 不是尾調(diào)用1: 
  2. - (NSInteger)funcA:(NSInteger)num {      
  3. NSInteger num = [self funcB:(num)];      
  4. return num;// 不是尾調(diào)用->***一步是返回一個值,而不是調(diào)用一個函數(shù) 

反例解釋:不是尾調(diào)用。因為***一步是返回一個值,而不是僅僅調(diào)用一個函數(shù)。

 
 
 
 
  1. // 不是尾調(diào)用2:
  2. - (NSInteger)funcA:(NSInteger)num {    
  3. return [self funcB:(num)] + 1;// 不是尾調(diào)用->原因:末尾有+1操作}

反例解釋:不是尾調(diào)用。因為***一步不僅調(diào)用了函數(shù)還有 +1 操作。

2. OC的尾調(diào)用優(yōu)化體現(xiàn)在哪里?

小編準備了一個Demo:通過“斷點”和“當前內(nèi)存情況”查看有無尾調(diào)用優(yōu)化。

場景一:無優(yōu)化(因為追加了.0,不屬于尾調(diào)用)

無優(yōu)化Demo效果圖:

這種場景下,每次函數(shù)調(diào)用一直在進棧,不斷申請??臻g,***會棧溢出,最終導致崩潰。 空間復雜度O(n),時間復雜度O(n)。

圖解如下:

場景二:有尾調(diào)用優(yōu)化

優(yōu)化Demo效果圖:

這種場景下,每次函數(shù)調(diào)用一直在重用棧幀,不申請??臻g??臻g復雜度O(1),時間復雜度O(n)。

圖解如下:

3. OC是如何實現(xiàn)尾調(diào)用優(yōu)化的?

這次討論起因于《Effective Objective-C 2.0》的原文:

如果某函數(shù)的***一項操作是調(diào)用另外一個函數(shù),那么就可以運用 “尾調(diào)用優(yōu)化”技術(shù)。編譯器會生成調(diào)轉(zhuǎn)至另一函數(shù)所需的指令碼,而且不會向調(diào)用堆棧中推入新的 “棧幀”(frame stack)。只有當某函數(shù)的***一個操作僅僅是調(diào)用其他函數(shù)而 不會將其返回值另作他用時,才能執(zhí)行 “尾調(diào)用優(yōu)化”。

這項優(yōu)化對 objc_msgSend非常關鍵,如果不這么做的話,那么每次調(diào)用Objective-C方法之前,都需要為調(diào)用objc_msgSend函數(shù)準備“棧幀”,大家在“棧蹤跡”(stack trace)中可以看到這種“棧幀”。此外,如果不優(yōu)化,還會過早地發(fā)生“棧溢出”(stack overflow)現(xiàn)象。

作者對尾調(diào)用的描述十分精簡。在這里,QiShare團隊對這段話進行了詳細的分析:

(1)尾調(diào)用優(yōu)化的本質(zhì):很簡單,就是棧幀的復用。

(2)尾調(diào)用優(yōu)化的條件有三點:

  • 尾調(diào)用函數(shù)不需要訪問當前棧幀中的變量。(變量可以作為形參,但是不能作為實參)
  • 尾調(diào)用返回后,函數(shù)沒有語句需要執(zhí)行。(***一步僅僅只能執(zhí)行一個函數(shù))
  • 尾調(diào)用結(jié)果就是函數(shù)的返回值。(不能有別的“附加品”,***一步僅僅只能是執(zhí)行一個函數(shù))

(3)函數(shù)調(diào)用的過程:函數(shù)調(diào)用會在內(nèi)存中申請一塊“棧幀”,保存調(diào)用的地址和內(nèi)部變量等信息。如果函數(shù)A內(nèi)部調(diào)用函數(shù)B,那么在函數(shù)A的棧幀上就會加上一個函數(shù)B的棧幀。如果函數(shù)B再調(diào)用了函數(shù)C,那么函數(shù)A的棧幀上就會有序加上函數(shù)B和函數(shù)C的棧幀。如果C運行結(jié)束了,返回到函數(shù)B,C的棧幀才會消失。

(4)尾調(diào)用優(yōu)化實現(xiàn)原理:當函數(shù)A的***一步僅僅是調(diào)用另一個函數(shù)B時(或者調(diào)用自身函數(shù)A),這時,因為函數(shù)A的位置信息和內(nèi)部變量已經(jīng)不會再用到了,直接把函數(shù)A的棧幀交給函數(shù)B使用。

尾調(diào)用優(yōu)化關鍵圖解:

總結(jié):

  • 尾調(diào)用:某個函數(shù)的***一步僅僅調(diào)用了一個函數(shù)(可以是自身,可以是另一個函數(shù))。
  • OC的尾調(diào)用優(yōu)化的本質(zhì)是:棧幀的復用
  • 尾調(diào)用優(yōu)化實現(xiàn)原理:當函數(shù)A的***一步僅僅是調(diào)用另一個函數(shù)B時(或者調(diào)用自身函數(shù)A),這時,因為函數(shù)A的位置信息和內(nèi)部變量已經(jīng)不會再用到了,直接把函數(shù)A的棧幀交給函數(shù)B使用。

PS:尾調(diào)用優(yōu)化在Release模式下才會有,Debug模式下沒有。

源碼地址: https://github.com/QiShare/QiRecursiveDemo.git

【本文是專欄機構(gòu)360技術(shù)的原創(chuàng)文章,微信公眾號“360技術(shù)( id: qihoo_tech)”】


分享題目:iOSobjc_msgSend尾調(diào)用優(yōu)化機制
當前路徑:http://m.5511xx.com/article/djhsooi.html