06-go数据类型内存结构-chan

5. chan

var var_chan = make(chan int ,1)
func func1(){
...
var var2_chan = make(chan int ,3)
...
}

1、通过runtime.makechan()创建channel。

2、第一个参数为chan类型信息
3、返回值类型为*hchan
即: chan变量实际为一个hchan指针
由全局变量也可以看出。

func makechan(t *chantype, size int) *hchan {
    ...
    var c *hchan
    ...
    return c
}
"".var_chan SBSS size=8
0x014f 00335 (type.go:48)       LEAQ    type.chan int(SB), AX
0x0156 00342 (type.go:48)       PCDATA  $2, $0
0x0156 00342 (type.go:48)       MOVQ    AX, (SP)
0x015a 00346 (type.go:48)       MOVQ    $3, 8(SP)
0x0163 00355 (type.go:48)       CALL    runtime.makechan(SB)
0x0168 00360 (type.go:48)       PCDATA  $2, $1
0x0168 00360 (type.go:48)       MOVQ    16(SP), AX  //返回值为 *hchan 类型
0x016d 00365 (type.go:48)       PCDATA  $2, $0
0x016d 00365 (type.go:48)       PCDATA  $0, $5
0x016d 00365 (type.go:48)       MOVQ    AX, "".var2_chan+144(SP)

chan类型信息

type chantype struct {  //64 字节
	typ  _type      //48 字节
	elem *_type     //8  字节
	dir  uintptr    //8 字节
}

类型信息对应汇编

type..namedata.*chan int- SRODATA dupok size=12
        0x0000 00 00 09 2a 63 68 61 6e 20 69 6e 74              ...*chan int
type.*chan int SRODATA dupok size=56
        0x0000 08 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00  ................
        0x0010 ed 7b ed 3b 00 08 08 36 00 00 00 00 00 00 00 00  .{.;...6........
        0x0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
        0x0030 00 00 00 00 00 00 00 00                          ........
        rel 24+8 t=1 runtime.algarray+80
        rel 32+8 t=1 runtime.gcbits.01+0
        rel 40+4 t=5 type..namedata.*chan int-+0
        rel 48+8 t=1 type.chan int+0
type.chan int SRODATA dupok size=64
        0x0000 08 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00  ................
        0x0010 91 55 cb 71 02 08 08 32 00 00 00 00 00 00 00 00  .U.q...2........
        0x0020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
        0x0030 00 00 00 00 00 00 00 00 03 00 00 00 00 00 00 00  ................
        rel 24+8 t=1 runtime.algarray+80
        rel 32+8 t=1 runtime.gcbits.01+0
        rel 40+4 t=5 type..namedata.*chan int-+0
        rel 44+4 t=6 type.*chan int+0
        rel 48+8 t=1 type.int+0

5.1 通过runtime.makechan

src\runtime\chan.go
func makechan(t *chantype, size int) *hchan {
	elem := t.elem

	// compiler checks this but be safe.
	if elem.size >= 1<<16 {
		throw("makechan: invalid channel element type")
	}
	if hchanSize%maxAlign != 0 || elem.align > maxAlign {
		throw("makechan: bad alignment")
	}

	mem, overflow := math.MulUintptr(elem.size, uintptr(size))
	if overflow || mem > maxAlloc-hchanSize || size < 0 {
		panic(plainError("makechan: size out of range"))
	}

	// Hchan does not contain pointers interesting for GC when elements stored in buf do not contain pointers.
	// buf points into the same allocation, elemtype is persistent.
	// SudoG's are referenced from their owning thread so they can't be collected.
	// TODO(dvyukov,rlh): Rethink when collector can move allocated objects.
	var c *hchan
	switch {
	case mem == 0:
		// Queue or element size is zero.
		c = (*hchan)(mallocgc(hchanSize, nil, true))
		// Race detector uses this location for synchronization.
		c.buf = c.raceaddr()
	case elem.kind&kindNoPointers != 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)
	}

	c.elemsize = uint16(elem.size)
	c.elemtype = elem
	c.dataqsiz = uint(size)

	if debugChan {
		print("makechan: chan=", c, "; elemsize=", elem.size, "; elemalg=", elem.alg, "; dataqsiz=", size, "\n")
	}
	return c
}
上一篇:go的select


下一篇:从零开始学Go之并发(二):通道