runtime: do not scan maps when k/v do not contain pointers

Currently we scan maps even if k/v does not contain pointers.
This is required because overflow buckets are hanging off the main table.
This change introduces a separate array that contains pointers to all
overflow buckets and keeps them alive. Buckets themselves are marked
as containing no pointers and are not scanned by GC (if k/v does not
contain pointers).

This brings maps in line with slices and chans -- GC does not scan
their contents if elements do not contain pointers.

Currently scanning of a map[int]int with 2e8 entries (~8GB heap)
takes ~8 seconds. With this change scanning takes negligible time.

Update #9477.

Change-Id: Id8a04066a53d2f743474cad406afb9f30f00eaae
Reviewed-on: https://go-review.googlesource.com/3288
Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
Dmitry Vyukov 2015-01-26 21:04:41 +03:00
parent 561ce92fa0
commit 85e7bee19f
3 changed files with 110 additions and 35 deletions

View file

@ -1469,9 +1469,8 @@ func MapOf(key, elem Type) Type {
// Make a map type.
var imap interface{} = (map[unsafe.Pointer]unsafe.Pointer)(nil)
prototype := *(**mapType)(unsafe.Pointer(&imap))
mt := new(mapType)
*mt = *prototype
*mt = **(**mapType)(unsafe.Pointer(&imap))
mt.string = &s
mt.hash = fnv1(etyp.hash, 'm', byte(ktyp.hash>>24), byte(ktyp.hash>>16), byte(ktyp.hash>>8), byte(ktyp.hash))
mt.key = ktyp
@ -1575,7 +1574,7 @@ func (gc *gcProg) appendProg(t *rtype) {
for i := 0; i < c; i++ {
gc.appendProg(t.Field(i).Type.common())
}
if gc.size > oldsize + t.size {
if gc.size > oldsize+t.size {
panic("reflect: struct components are larger than the struct itself")
}
gc.size = oldsize + t.size
@ -1650,6 +1649,12 @@ const (
)
func bucketOf(ktyp, etyp *rtype) *rtype {
// See comment on hmap.overflow in ../runtime/hashmap.go.
var kind uint8
if ktyp.kind&kindNoPointers != 0 && etyp.kind&kindNoPointers != 0 {
kind = kindNoPointers
}
if ktyp.size > maxKeySize {
ktyp = PtrTo(ktyp).(*rtype)
}
@ -1679,6 +1684,7 @@ func bucketOf(ktyp, etyp *rtype) *rtype {
b := new(rtype)
b.size = gc.size
b.kind = kind
b.gc[0], _ = gc.finalize()
s := "bucket(" + *ktyp.string + "," + *etyp.string + ")"
b.string = &s