This is a creation in Article, where the information may have evolved or changed.
Main Association initialization
The main association of Golang refers to the process of running the main function, while the Sub-association refers to the co-process created by the master during the program's run. Each thread (m) will have only one main coprocessor, and the sub-process may be a lot.
The sub-process and the main process have almost no difference in concept and internal implementations, except that their initial stack sizes are different.
Let's take a look at the example of the main thread stack generated during the test. I generated a master in my test code, and the disassembly code saw him look like this:
Main process Start
Analysis Connector (Libinit ()) discovers the entry function of the Go Program is _rt0_amd64_linux (Linux AMD64 machine)
Sub-process initialization
The Golang sub-process stack is also created when the co-process is created, with the following code:
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 {//create CO stacks NEWG = Malg (_stackmin) Casgstatus ( NEWG, _gidle, _gdead) allgadd (NEWG)//publishes with a g->status of gdead so GC scanner doesn ' t look at Uniniti Alized stack. } ... totalsize: = 4*regsize + uintptr (siz)//Extra space in case of reads slightly beyond frame if Haslinkre Gister {totalsize + = ptrsize} totalsize + =-totalsize & (spAlign-1)//Align to spalign//new co-stack top count Calculate the base address of the stack minus the space sp: = newg.stack.hi-totalsize Sparg: = SP if haslinkregister {//caller ' s LR * (*unsafe. Pointer) (unsafe. Pointer (sp)) = Nil Sparg + = ptrsize} ...//set top of stack for new coprocessor 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.stkb AR = stackalloc (UInt32 (stacksize)})//Set Stackguard, re-request a new stack newg.stackguard0 = Newg.stack when the coprocessor stack is not enough. Lo + _stackguard newg.stackguard1 = ^uintptr (0) Newg.stackalloc = UIntPtr (stacksize)} return NEWG}
In the go1.5.1 version, the _stackmin size is defined as 2048 (or 8192 in the 1.3.2 version), or the initial stack size of each association is 2KB, which is quite small. The benefit of narrowing this value is that even if many of the processes are created, it does not cause a sharp increase in memory usage.
In addition, after the stacks space is allocated, some other initialization is required, mainly the setting of the stacks top and the setting of the stack protection.
The method of setting the top of the stack is relatively simple, and the starting address of the current stack is subtracted from the space occupied by the parameter (note that the stack is extended from a high address to a low address).
Stack protection setting refers to setting a critical point, when the SP reaches the critical point when the stack space may be insufficient, need to do stack expansion. The current version of the coprocessor stack protects the size of 640B.
Here are the details of the process that I printed after I added some debugging information to the source code to create the stack:
create goroutine, stack:{stackLow: 859530534912, stackHi:859530536928, sp:859530536880, stackguard:859530535552}
Based on the above analysis and the printing information can roughly outline the process initialization state stack:
Https://tracymacding.gitbooks.io/implementation-of-golang/stack/stack_overview.html https:// Tracymacding.gitbooks.io/implementation-of-golang/stack/stack_enlarge.html