Skip to content

proposal: runtime: add way to clear and reuse a map's working storage #45328

@AsterDY

Description

@AsterDY

func makemap(t *maptype, hint int, h *hmap) *hmap {
I see runtime.makemap() gives a way to reuse old hmap's buckets, but it is only used when mallocating small maps on stack at present. Why not open this shortcut to users for memory reusing? Actually I only need exporting runtime.makemap() and runtime.clearmap() to achieve this goal:

func resetMap(mtyp *mapType, ptr unsafe.Pointer) {
	m := *(*unsafe.Pointer)(ptr)
	if m == nil {
		return
	}

	hm := (*hmap)(m)
	old := hm.B
	mapclear(mtyp, hm)

	hm = makemap(mtyp, 0, hm)
	hm.B = old
	*(*unsafe.Pointer)(ptr) = m
}

It works fine and benefits much on big maps. This is the benchmark results I got on operating a 1000-keys map (one op includes make(map[int]interface{}), set 1000 keys and get 1000 keys):

func BenchmarkMap1000_ResetAndSet(b *testing.B) {
	var pool = sync.Pool{
		New: func() interface{} {
			m := make(map[int]interface{}, 0)
			return &m
		},
	}

	for n := 0; n < b.N; n++ {
		x := pool.Get()
		obj, _ := x.(*map[int]interface{})
		m := *obj
		for i := 0; i < 1000; i++ {
			m[i] = i
			if ni, ok := m[i]; !ok || ni != i {
				b.Fatalf("exp:%v, got:%v", i, ni)
			}
		}
		resetMap(mtype(unpackEface(m).typ), unsafe.Pointer(obj))
		pool.Put(obj)
	}
}

func BenchmarkMap1000_MallocAndSet(b *testing.B) {
	var obj map[int]interface{}

	for n := 0; n < b.N; n++ {
		obj = make(map[int]interface{})
		for i := 0; i < 1000; i++ {
			obj[i] = i
			if ni, ok := obj[i]; !ok || ni != i {
				b.Fatalf("exp:%v, got:%v", i, ni)
			}
		}
	}

	obj[1] = 1
}

//-------------RESULTS----------------
goos: darwin
goarch: amd64
pkg: code.byted.org/gopkg/memset
cpu: Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
BenchmarkMap1000_ResetAndSet-16     	   23750	     47376 ns/op	    5957 B/op	     744 allocs/op
BenchmarkMap1000_MallocAndSet-16    	    9390	    119347 ns/op	  128288 B/op	     785 allocs/op

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions