From 7e26a2d9a80b825d019c2cdaf6437d89001506a9 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 14 May 2015 17:27:04 -0400 Subject: [PATCH] runtime: allocate map element zero values for reflect-created types on demand Preallocating them in reflect means that (1) if you say _ = PtrTo(ArrayOf(1000000000, reflect.TypeOf(byte(0)))), you just allocated 1GB of data (2) if you say it again, that's *another* GB of data. The only use of t.zero in the runtime is for map elements. Delay the allocation until the creation of a map with that element type, and share the zeros. The one downside of the shared zero is that it's not garbage collected, but it's also never written, so the OS should be able to handle it fairly efficiently. Change-Id: I56b098a091abf3ac0945de28ebef9a6c08e76614 Reviewed-on: https://go-review.googlesource.com/10111 Reviewed-by: Keith Randall --- src/reflect/type.go | 9 -------- src/runtime/hashmap.go | 48 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 9 deletions(-) diff --git a/src/reflect/type.go b/src/reflect/type.go index 5a43805626..bffe2595dd 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -1087,7 +1087,6 @@ func (t *rtype) ptrTo() *rtype { p.uncommonType = nil p.ptrToThis = nil - p.zero = unsafe.Pointer(&make([]byte, p.size)[0]) p.elem = t ptrMap.m[t] = p @@ -1467,7 +1466,6 @@ func ChanOf(dir ChanDir, t Type) Type { ch.elem = typ ch.uncommonType = nil ch.ptrToThis = nil - ch.zero = unsafe.Pointer(&make([]byte, ch.size)[0]) return cachePut(ckey, &ch.rtype) } @@ -1530,7 +1528,6 @@ func MapOf(key, elem Type) Type { mt.reflexivekey = isReflexive(ktyp) mt.uncommonType = nil mt.ptrToThis = nil - mt.zero = unsafe.Pointer(&make([]byte, mt.size)[0]) return cachePut(ckey, &mt.rtype) } @@ -1610,7 +1607,6 @@ func FuncOf(in, out []Type, variadic bool) Type { ft.string = &str ft.uncommonType = nil ft.ptrToThis = nil - ft.zero = unsafe.Pointer(&make([]byte, ft.size)[0]) funcLookupCache.m[hash] = append(funcLookupCache.m[hash], &ft.rtype) return ft @@ -1857,7 +1853,6 @@ func SliceOf(t Type) Type { slice.elem = typ slice.uncommonType = nil slice.ptrToThis = nil - slice.zero = unsafe.Pointer(&make([]byte, slice.size)[0]) return cachePut(ckey, &slice.rtype) } @@ -1913,10 +1908,6 @@ func ArrayOf(count int, elem Type) Type { array.fieldAlign = typ.fieldAlign array.uncommonType = nil array.ptrToThis = nil - if array.size > 0 { - zero := make([]byte, array.size) - array.zero = unsafe.Pointer(&zero[0]) - } array.len = uintptr(count) array.slice = slice.(*rtype) diff --git a/src/runtime/hashmap.go b/src/runtime/hashmap.go index 9ca33992bb..2b3af301b3 100644 --- a/src/runtime/hashmap.go +++ b/src/runtime/hashmap.go @@ -233,6 +233,9 @@ func makemap(t *maptype, hint int64, h *hmap, bucket unsafe.Pointer) *hmap { throw("need padding in bucket (value)") } + // make sure zero of element type is available. + mapzero(t.elem) + // find size parameter which will hold the requested # of elements B := uint8(0) for ; hint > bucketCnt && float32(hint) > loadFactor*float32(uintptr(1)<2GB zero on 32-bit machine + throw("map element too large") + } + } + zerobuf.p = (*byte)(persistentalloc(zerobuf.size, 64, &memstats.other_sys)) + } + atomicstorep(unsafe.Pointer(&t.zero), unsafe.Pointer(zerobuf.p)) + unlock(&zerobuf.lock) +}