go在stack上幹了神馬?

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
  1. 對這個話題已經有深入理解的童鞋請繞道;
  2. 對這個話題感興趣,且有極強學習能力的同學請閱讀這裡,並且不用回來了。
  3. 其他和我一樣愚笨的IT民工們,繼續向前沖吧……
  4. 【2013年3月21日】以下關於 stackless 的描述有致命的腦殘錯誤,請忽略。感謝 @minux 指出。

首先,來看一段神奇的 golang 代碼:

package mainvar (    i = 1)func main() {    i = i + 1    print(i, "\n")    main()}


熟悉 c 語言的人都知道,如果在 c 語言中編譯執行類似的代碼,程式最終會發生棧溢出(stack overflow),從而導致段錯誤(segmentation fault)。在 32 位環境下(我只有 32 位的實驗環境)編譯連結並執行這段代碼,預期的“段錯誤”並沒有出現。

程式長時間穩定的執行。同時,利用 top 命令,會看到程式所使用的記憶體不斷上升,絲毫沒有減少的痕迹。

祭出神器 gdb,來看一下這個 go 程式到底做了什麼。

gdb stackless...(gdb) b main.main...(gdb) r...(gdb) disassemble

當輸入 disassemble 命令後,gdb 幫我們反編譯了程式碼:

   0x08048c00 <+0>:mov    %gs:0x0,%ecx   0x08048c07 <+7>:mov    -0x8(%ecx),%ecx   0x08048c0a <+10>:cmp    (%ecx),%esp   0x08048c0c <+12>:ja     0x8048c17 <main.main+23>   0x08048c0e <+14>:xor    %edx,%edx   0x08048c10 <+16>:xor    %eax,%eax   0x08048c12 <+18>:call   0x8049515 <runtime.morestack>   0x08048c17 <+23>:sub    $0x1c,%esp   0x08048c1a <+26>:mov    0x806c00c,%eax   0x08048c20 <+32>:inc    %eax   0x08048c21 <+33>:mov    %eax,0x806c00c   0x08048c27 <+39>:cltd      0x08048c28 <+40>:mov    %eax,(%esp)   0x08048c2b <+43>:mov    %edx,0x4(%esp)   0x08048c2f <+47>:call   0x804ef1b <runtime.printint>   0x08048c34 <+52>:lea    0x80557b0,%esi   0x08048c3a <+58>:lea    (%esp),%edi   0x08048c3d <+61>:cld       0x08048c3e <+62>:movsl  %ds:(%esi),%es:(%edi)   0x08048c3f <+63>:movsl  %ds:(%esi),%es:(%edi)   0x08048c40 <+64>:call   0x804f099 <runtime.printstring>   0x08048c45 <+69>:call   0x8048c00 <main.main>   0x08048c4a <+74>:add    $0x1c,%esp   0x08048c4d <+77>:ret 

main.main+0到main.main+12處,我們看到取了兩個值進行比較,當 (%ecx)大於%esp時,跳轉到main.main+23。

main.main+23到main.main+64處,顯然是我們程式的邏輯處理:變數i自加一、列印i、列印”\n”。

main.main+69再次調用地址 0x8048c00 的 main.main。

除了main.main+0到main.main+12的比較,main.main+14到main.main+18對 runtime.morestack 的調用外,這和一個普通的程式並無二至。

那麼程式一開始比較兩個資料和調用 runtime.morestack 是什麼呢?

原來在程式一開始先比較了棧限制和已經使用的棧的大小(%esp)。當棧限制大於已經使用的棧的時候,說明空間充裕,則直接跳轉到實際代碼處執行(+23)。當棧限制小於等於時已經使用的棧時,執行 runtime.morestack(+18)申請更多的棧空間。

在 $(GOROOT)/src/pkg/runtime/stack.h 中,有略微詳細的說明。

由此看來 golang 實現的並不是 stackless,而是在每次函數調用前判斷棧空間是否足夠,如果發現棧空間不夠用,就立刻申請新的棧空間使用。當函數退出時,才釋放這些棧空間。

還是在 gdb 中,執行:

(gdb) b runtime.morestack...(gdb) r

在函數調用 100 多次後(猜測 32 位跟 64 位元應當不同,沒試),觸發了 runtime.morestack 申請新的棧空間。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.