Mar 19, 2021

[Go] hchan data structure

Reference:
https://groups.google.com/g/golang-nuts/c/y_MZqc_WHnw/m/S64o1iPuCQAJ



Quote:

The garbage collector has to always know exactly where pointers are stored in memory.
We could in principle use contiguous allocation for the case where the element type contains pointers, but we would have to build a description that tells the garbage collector exactly where those pointers are. Those descriptions are built by the compiler (on tip, the code is in cmd/compile/internal/reflectdata/reflect.go), so the compiler would have to build a new descriptor for every channel type with an element type that contains pointers.

And the descriptor would have to vary based on the channel size, so it would be based not just on the channel type but also on the argument passed to "make".

Of course the argument passed to "make" can be a variable, so that adds another complication.


code snippet:

case elem.ptrdata == 0:
   // Elements do not contain pointers.
   // Allocate hchan and buf in one call.
   c = (*hchan)(mallocgc(hchanSize+mem, nil, true))
   c.buf = add(unsafe.Pointer(c), hchanSize)
default:
   // Elements contain pointers.
   c = new(hchan)
   c.buf = mallocgc(mem, elem, true)
}

Quote: 
AFAIK when there's no pointer in elem (the channel's element's type), we can cheat/optimize (call as you wish), and allocate the channel's backing memory AND all it's elements' memory at once, AS A BYTE ARRAY (nil is the second argument of mallocgc).
Then we can play unsafe tricks an treat it as proper channel and its buffer.
When there's pointer somewhere in the element's type, then - as the garbage collector must know each and every pointer's placement - we don't play tricks, and give mallocgc the proper type information, and allocate the element buffer separate from the channel backing. You'd have to repeat mallocgc's functionality to provide the gc with proper information, just to save one allocation. That'd be too much work for less gain.

Quote:
When the code you showed calls mallocgc, it passes the type descriptor
for the channel element type. This is called "elem" in the code.
This type descriptor was created by the compiler.

If the runtime code allocated both the channel data structure and the
buffer in a single memory allocation, it would need to have a type
descriptor that combined the channel data structure with the element
type. Not only that, this new type descriptor would change based on
the argument passed to make. In the existing code, that is not
necessary; when mallocgc is passed a type descriptor to allocate a
size that is larger than the type, it understands that it is
allocating an array. That wouldn't work for an allocation that shares
the channel data structure with the channel buffer.

I don't know what you mean when you say "gc would find the descriptor
later with more time." The compiler would have to create the
descriptor at compile time, so that the runtime code could use that
type descriptor to allocate the memory. The gc can't find the
descriptor later.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.