博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
golang map 底层部分理解
阅读量:6267 次
发布时间:2019-06-22

本文共 3634 字,大约阅读时间需要 12 分钟。

部分参考链接

bucket理解

初始的bucket数量通过

// makemap implements Go map creation for make(map[k]v, hint).// If the compiler has determined that the map or the first bucket// can be created on the stack, h and/or bucket may be non-nil.// If h != nil, the map can be created directly in h.// If h.buckets != nil, bucket pointed to can be used as the first bucket.func makemap(t *maptype, hint int, h *hmap) *hmap {	mem, overflow := math.MulUintptr(uintptr(hint), t.bucket.size)	if overflow || mem > maxAlloc {    	hint = 0	}	// initialize Hmap	if h == nil {    	h = new(hmap)	}	h.hash0 = fastrand()	// Find the size parameter B which will hold the requested # of elements.	// For hint < 0 overLoadFactor returns false since hint < bucketCnt.	B := uint8(0)	for overLoadFactor(hint, B) {    	B++	}	h.B = B}复制代码

即个数由传入的参数hint,通过overLoadFactor函数计算得来一个B,B决定了初始bucket数量,这些buckets以数组形式存储,每一个bucket组成如下:

  • 一个包含8个uint8数组,对应存储的kv的key
  • key1key2...key8val1val2...val8
  • 指向下一个bucket的指针
  • 每一个map对应的maptype类型中的bucketsize的实现位于reflect包的type.go文件中,具体代码如下:
func MapOf(key, elem Type) Type {	// Make a map type. 即编译器通过这里生成了对应该map的maptype	var imap interface{} = (map[unsafe.Pointer]unsafe.Pointer)(nil)	mt := **(**mapType)(unsafe.Pointer(&imap))	mt.key = ktyp	mt.elem = etyp	mt.bucket = bucketOf(ktyp, etyp)	mt.bucketsize = uint16(mt.bucket.size)  // bucketsize 在这里赋值,其中mt.bucket的结构bucketof()见下文	ti, _ := lookupCache.LoadOrStore(ckey, &mt.rtype)	return ti.(Type)}复制代码

bucketof()定义如下(位于reflect包的type.go中):

func bucketOf(ktyp, etyp *rtype) *rtype {	// See comment on hmap.overflow in ../runtime/map.go.	// Prepare GC data if any.	// A bucket is at most bucketSize*(1+maxKeySize+maxValSize)+2*ptrSize bytes,	// or 2072 bytes, or 259 pointer-size words, or 33 bytes of pointer bitmap.	// Note that since the key and value are known to be <= 128 bytes,	// they are guaranteed to have bitmaps instead of GC programs.	var gcdata *byte	var ptrdata uintptr	var overflowPad uintptr        // 这里即为bucketsize的最终实现,8字节的hashtop,所有的key value占用空间,可能的pad填充,指向下一个bucket的指针	size := bucketSize*(1+ktyp.size+etyp.size) + overflowPad + ptrSize	b := &rtype{	    align:   ptrSize,	    size:    size,	    kind:    kind,    	ptrdata: ptrdata,    	gcdata:  gcdata,	}	s := "bucket(" + ktyp.String() + "," + etyp.String() + ")"	b.str = resolveReflectName(newName(s, "", false))	return b}复制代码

指向下一个bucket的指针赋值方式

func (h *hmap) newoverflow(t *maptype, b *bmap) *bmap {	var ovf *bmap	if h.extra != nil && h.extra.nextOverflow != nil {    	// We have preallocated overflow buckets available.    	// See makeBucketArray for more details.    	ovf = h.extra.nextOverflow    	if ovf.overflow(t) == nil {    		// We are not at the end of the preallocated overflow buckets. Bump the pointer.    		h.extra.nextOverflow = (*bmap)(add(unsafe.Pointer(ovf), uintptr(t.bucketsize)))    	} else {    		// This is the last preallocated overflow bucket.    		// Reset the overflow pointer on this bucket,    		// which was set to a non-nil sentinel value.    		ovf.setoverflow(t, nil)    		h.extra.nextOverflow = nil    	}	} else {    	ovf = (*bmap)(newobject(t.bucket))	}	h.incrnoverflow()	if t.bucket.kind&kindNoPointers != 0 {    	h.createOverflow()    	*h.extra.overflow = append(*h.extra.overflow, ovf)	}	b.setoverflow(t, ovf) // 最终通过这里的setoverflow将新建的bucket绑定到b的后面	return ovf}func (b *bmap) setoverflow(t *maptype, ovf *bmap) {    // 减去的sys.PtrSize即为链接到后一个bucket的指针的大小,这样得到的刚好是该指针的地址	*(**bmap)(add(unsafe.Pointer(b), uintptr(t.bucketsize)-sys.PtrSize)) = ovf}// 取overflow同样的道理func (b *bmap) setoverflow(t *maptype, ovf *bmap) {	*(**bmap)(add(unsafe.Pointer(b), uintptr(t.bucketsize)-sys.PtrSize)) = ovf}复制代码

持续更新中......

转载地址:http://xzjpa.baihongyu.com/

你可能感兴趣的文章
maven常用构建命令
查看>>
C#:关联程序和文件
查看>>
推荐科研软件
查看>>
gradle
查看>>
如何取消未知类型文件默认用记事本打开
查看>>
[Javascript] Immute Object
查看>>
Java 关于finally、static
查看>>
Posix mq和SystemV mq区别
查看>>
P6 EPPM Manual Installation Guide (Oracle Database)
查看>>
XMPP协议、IM、客户端互联详解
查看>>
PHP写文件函数
查看>>
mysql的sql_mode合理设置
查看>>
函数连续性与可导性
查看>>
linux下libevent安装
查看>>
用ip来获得用户所在地区信息
查看>>
卡尔曼滤波
查看>>
linux下面覆盖文件,如何实现直接覆盖,不提示
查看>>
CSS3阴影 box-shadow的使用和技巧总结
查看>>
Linux下高cpu解决方案
查看>>
SQL事务用法begin tran,commit tran和rollback tran的用法
查看>>