2020-11-19:go中,defer原理是什么?

福哥答案2020-11-19:

    • 什么是defer
      • defer是go語言提供的一種用于注冊延遲調(diào)用的機(jī)制:讓函數(shù)或者語句在當(dāng)前函數(shù)執(zhí)行完畢(包括return正常結(jié)束或者panic導(dǎo)致的異常結(jié)束)之后執(zhí)行。
      • defer語句通常用于一些成對的操作場景,打開/關(guān)閉連接,加鎖/解鎖,打開文件/關(guān)閉文件等等
      • defer在一些需要回收資源的場景中非常有用
    • 為什么需要defer
      • 有效防止內(nèi)存泄漏
    • defer底層原理
      • 每次defer語句在執(zhí)行的時(shí)候,都會將函數(shù)進(jìn)行“壓棧”,函數(shù)參數(shù)會被拷貝下來。當(dāng)外層函數(shù)退出時(shí),defer函數(shù)會按照定義的順序逆序執(zhí)行。如果defer執(zhí)行的函數(shù)為nil,那么會在最終調(diào)用函數(shù)中產(chǎn)生panic。
      • 編譯器會把 defer 語句翻譯成對 deferproc 函數(shù)的調(diào)用,同時(shí),編譯器也會在使用了 defer 語句的 go 函數(shù)的末尾插入對 deferreturn 函數(shù)的調(diào)用。
      • 每一個(gè)goroutine結(jié)構(gòu)體中都有一個(gè)_defer 指針變量用來存放defer單鏈表。defer保存用什么數(shù)據(jù)結(jié)構(gòu)?回答棧過不了面試官那關(guān),defer單鏈表應(yīng)該能過關(guān)。_defer 結(jié)構(gòu)體如下:
        • siz:所有傳入?yún)?shù)的總大小。
        • started:該 defer 是否已經(jīng)執(zhí)行過。
        • heap:表明該defer是否存儲在heap上。
        • sp:函數(shù)棧指針寄存器,一般指向當(dāng)前函數(shù)棧的棧頂。
        • pc:程序計(jì)數(shù)器,有時(shí)稱為指令指針(IP),線程利用它來跟蹤下一個(gè)要執(zhí)行的指令。在大多數(shù)處理器中,PC指向的是下一條指令,而不是當(dāng)前指令。
        • fn:指向傳入的函數(shù)地址和參數(shù)。
        • _panic:指向 _panic 鏈表。
        • link:指向 _defer 鏈表。
      • 為什么defer要按照定義的順序逆序執(zhí)行:后面定義的函數(shù)可能會依賴前面的資源,所以要先執(zhí)行。如果前面先執(zhí)行,釋放掉這個(gè)依賴,那后面的函數(shù)就不能找到它的依賴了。
      • defer函數(shù)定義時(shí),對外部變量的引用方式有兩種,分別是函數(shù)參數(shù)以及作為閉包引用。在作為函數(shù)參數(shù)的時(shí)候,在defer定義時(shí)就把值傳遞給defer,并被cache起來。如果是作為閉包引用,則會在defer真正調(diào)用的時(shí)候,根據(jù)整個(gè)上下文云確定當(dāng)前的值。
      • defer后面的語句在執(zhí)行的時(shí)候,函數(shù)調(diào)用的參數(shù)會被保存起來,也就是復(fù)制一份。在真正執(zhí)行的時(shí)候,實(shí)際上用到的是復(fù)制的變量,也就是說,如果這個(gè)變量是一個(gè)“值類型”,那他就和定義的時(shí)候是一致的,如果是一個(gè)“引用”,那么就可能和定義的時(shí)候的值不一致
    • 利用defer原理
      • 利用defer先求值,再延遲調(diào)用的性質(zhì)
    • defer與return
    • defer語句的參數(shù)
      • defer語句表達(dá)式的值在定義的時(shí)候就已經(jīng)確定了
    • 閉包:由函數(shù)以及相關(guān)引用環(huán)境組合而成的實(shí)例,也就是說閉包=函數(shù)+引用環(huán)境
    • 匿名函數(shù):匿名函數(shù)就是我們說的閉包,它不能獨(dú)立存在,但可以直接調(diào)用或者賦值于某個(gè)變量。一個(gè)閉包,繼承了函數(shù)聲明時(shí)的作用域。在go語言中,所有的匿名函數(shù)都是閉包
  • defer配合recover
    • recover:異常捕獲,可以讓程序在引發(fā)panic的時(shí)候不會崩潰退出。在引發(fā)panic的時(shí)候,panic會停掉當(dāng)前正在執(zhí)行的程序,但是,在這之前,它會有序的執(zhí)行完當(dāng)前goroutine的defer列表的語句。所以我們通常在defer里面掛一個(gè)recover,防止程序直接掛掉,類似于try...catch.recover()函數(shù)只在defer的上下文中才有效,直接調(diào)用,會返回nil

評論,有好幾個(gè)參考地址

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容