It isn't just inlining that affects closures. Most programming languages with closures use several closure representations at the same time. The compiler picks among them depending on which representation gives the best program efficiency at runtime and depending on what information they statically know about the program at compile time. This makes your question inherently hard to answer precisely because the representation can change quite a lot even with small changes to the program text.
However, the original rules apply for the GC: roots are given as the global variables plus each pointer off of the stacks of the goroutines. Following these pointers transitively through the heap defines data which is live and thus not collectable. The compiler is responsible to make sure that this is an invariant when it compiles a closure. It must also follow the rules of a program stack: if a variable escapes its deallocation on the stack, that variable must be moved somewhere safe, typically the heap. In short: the GC essentially proposes a contract/invariant/protocol. If the compiler abides by that contract, it can do whatever it wants within the limits of what the contract says. On Wed, Mar 22, 2017 at 3:41 PM T L <tapir....@gmail.com> wrote: > > > On Wednesday, March 22, 2017 at 10:38:32 PM UTC+8, T L wrote: > > > > On Wednesday, March 22, 2017 at 7:49:39 PM UTC+8, Dave Cheney wrote: > > Well, that program isn't that simple because of the closure, but also > because it contains a data race > > Something like this is easier to reason about > > var x *int > > func main() { > var a int > x = &a > fmt.Println(*x) > } > > > or like this, :D > > package main > > func f(*int){ > var b int > // avoid f to be inlined. > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > b++ > } > > func main() { > var a int > f(&a) // &a escapes to heap > } > > > > > a simpler one > > package main > > func f(*int){ > for 1 < 0 {} // avoid f to be inlined. > > } > > func main() { > var a int > f(&a) // &a escapes to heap > } > > > On Wednesday, 22 March 2017 21:59:17 UTC+11, T L wrote: > > > > On Wednesday, March 22, 2017 at 6:40:53 PM UTC+8, Jesse McNelis wrote: > > On Wed, Mar 22, 2017 at 8:51 PM, T L <tapi...@gmail.com> wrote: > > > > More accurately, I think it should be: from the POV of a programmer, > it's > > globals, and things reachable from each goroutine. > > > > The only way to reach a value is through a variable in scope and the > only variables in scope are global or on the stack. > > 'heap pointers of local allocated memory blocks' are stored where ever > you put them, but you can only put them in places you can find by > using global or local stack variables. > > > So for this simple program: > > func main() { > var a int > go func() { // new goroutine > a++ > }() > > // ... > } > > a will be allocated on heap. > a is referenced by both stack of main and the new goroutine? > how is it referenced, the pointer of a's memory block is stored in both > stacks? > > -- > You received this message because you are subscribed to the Google Groups > "golang-nuts" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to golang-nuts+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.