Difference between the main goroutine and spawned goroutines of a Go program

浪尽此生 提交于 2019-11-30 15:29:30

Why is a Goroutine’s stack infinite:

One of the key features of Goroutines is their cost; they are cheap to create in terms of initial memory footprint (as opposed to the 1 to 8 megabytes with a traditional POSIX thread) and their stack grows and shrinks as necessary. This allows a Goroutine to start with a single 4096 byte stack which grows and shrinks as needed without the risk of ever running out.

There is however one detail I have withheld until now, which links the accidental use of a recursive function to a serious case of memory exhaustion for your operating system, and that is, when new stack pages are needed, they are allocated from the heap.

As your infinite function continues to call itself, new stack pages are allocated from the heap, permitting the function to continue to call itself over and over again. Fairly quickly the size of the heap will exceed the amount of free physical memory in your machine, at which point swapping will soon make your machine unusable.

The size of the heap available to Go programs depends on a lot of things, including the architecture of your CPU and your operating system, but it generally represents an amount of memory that exceeds the physical memory of your machine, so your machine is likely to swap heavily before your program ever exhausts its heap.

ref: http://dave.cheney.net/2013/06/02/why-is-a-goroutines-stack-infinite


Empty loop:

for{
}

uses 100% of a CPU Core, to wait for some operation depending to the use case you may use:
- sync.WaitGroup like this
- select {} like this
- channels
- time.Sleep


Is it because spawned goroutines stack size is very small (2Kbytes), and the main goroutine's much larger?

No, you may try these two samples to see the stack limit of goroutines are the same:
one main goroutine on The Go Playground,
try second goroutine on The Go Playground:

package main

import (
    "fmt"
    "sync"
)

var wg sync.WaitGroup

func main() {
    wg.Add(1)
    go run()
    wg.Wait()
}
func run() {
    s := &S{a: 1, b: 2}
    fmt.Println(s)
    wg.Done()
}

type S struct {
    a, b int
}

// String implements the fmt.Stringer interface
func (s *S) String() string {
    return fmt.Sprintf("%s", s) // Sprintf will call s.String()
}

both outputs are the same on the Go Playground:

runtime: goroutine stack exceeds 250_000_000-byte limit
fatal error: stack overflow

outputs on a PC with 8 GB RAM:

runtime: goroutine stack exceeds 1_000_000_000-byte limit
fatal error: stack overflow
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!