Golang協程棧初始化

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

主協程初始化

Golang的主協程指的是運行main函數的協程,而子協程指的是在程式運行過程中由主協程建立的協程。每個線程(m)只會有一個主協程,而子協程可能會有很多很多。

子協程和主協程在概念和內部實現上幾乎沒有任何區別,唯一的不同在於它們的初始棧大小不同。

我們先看看測試過程中產生的主協程堆棧樣本。我測試代碼中就產生了一個主協程,通過反組譯碼代碼看到他的樣子大概如下:

主協程啟動

分析連接器(libinit())發現go程式的入口函數是_rt0_amd64_linux(linux amd64機器)

子協程初始化

Golang子協程堆棧在協程被建立時也一併建立,代碼如下:

func newproc1(fn *funcval, argp *uint8, narg int32, nret int32, callerpc uintptr) *g {    _g_ := getg()    ......    _p_ := _g_.m.p.ptr()    newg := gfget(_p_)    if newg == nil {        // 建立協程棧        newg = malg(_StackMin)        casgstatus(newg, _Gidle, _Gdead)        allgadd(newg) // publishes with a g->status of Gdead so GC scanner doesn't look at uninitialized stack.    }    ......    totalSize := 4*regSize + uintptr(siz) // extra space in case of reads slightly beyond frame    if hasLinkRegister {        totalSize += ptrSize    }    totalSize += -totalSize & (spAlign - 1) // align to spAlign    // 新協程的棧頂計算,將棧的基地址減去參數佔用的空間    sp := newg.stack.hi - totalSize    spArg := sp    if hasLinkRegister {        // caller's LR        *(*unsafe.Pointer)(unsafe.Pointer(sp)) = nil        spArg += ptrSize    }    ...    // 設定建立協程的棧頂sp    newg.sched.sp = sp}// Allocate a new g, with a stack big enough for stacksize bytes.func malg(stacksize int32) *g {    newg := new(g)    if stacksize >= 0 {        stacksize = round2(_StackSystem + stacksize)        systemstack(func() {            newg.stack, newg.stkbar = stackalloc(uint32(stacksize))        })        // 設定stackguard,在協程棧不夠用時再重新申請新的棧        newg.stackguard0 = newg.stack.lo + _StackGuard        newg.stackguard1 = ^uintptr(0)        newg.stackAlloc = uintptr(stacksize)    }    return newg}

在go1.5.1版本中,_StackMin大小被定義為2048(而在1.3.2版本中該值還是8192),也即每個協程的初始堆棧大小為2KB,相當小了。縮小該值的好處是即使建立了很多的協程也不會導致記憶體使用量的急劇增長。

另外,在協程棧空間被分配出來後,還需要作一些其他的初始化,主要是協程棧頂的設定以及堆棧保護的設定。

  • 棧頂的設定方法比較簡單,將當前棧的起始地址減去參數佔用的空間即可(注意棧是從高地址向低地址延伸的)。

  • 棧保護的設定指的是設定一個臨界點,當sp到達該臨界點時認為棧空間可能會不足,需要進行棧擴容。目前的版本的協程棧保護大小事640B。

以下是我對源碼加入一些調試資訊後列印的協程建立堆棧的詳細資料:

create goroutine, stack:{stackLow: 859530534912, stackHi:859530536928, sp:859530536880, stackguard:859530535552}

根據上面的分析以及列印資訊可以大致勾勒出協程初始化狀態的堆棧:

https://tracymacding.gitbooks.io/implementation-of-golang/stack/stack_overview.html https://tracymacding.gitbooks.io/implementation-of-golang/stack/stack_enlarge.html

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.