github.com/scottcagno/storage@v1.8.0/pkg/util/memory.go (about) 1 package util 2 3 import ( 4 "reflect" 5 "sync" 6 ) 7 8 var processingPool = sync.Pool{ 9 New: func() interface{} { 10 return []reflect.Value{} 11 }, 12 } 13 14 func isNativeType(k reflect.Kind) bool { 15 switch k { 16 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, 17 reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, 18 reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128: 19 return true 20 } 21 return false 22 } 23 24 // Sizeof returns the estimated memory usage of object(s) not just the size of the type. 25 // On 64bit Sizeof("test") == 12 (8 = sizeof(StringHeader) + 4 bytes). 26 func Sizeof(objs ...interface{}) (sz uint64) { 27 refmap := make(map[uintptr]bool) 28 processing := processingPool.Get().([]reflect.Value)[:0] 29 for i := range objs { 30 processing = append(processing, reflect.ValueOf(objs[i])) 31 } 32 33 for len(processing) > 0 { 34 var val reflect.Value 35 val, processing = processing[len(processing)-1], processing[:len(processing)-1] 36 if !val.IsValid() { 37 continue 38 } 39 40 if val.CanAddr() { 41 refmap[val.Addr().Pointer()] = true 42 } 43 44 typ := val.Type() 45 46 sz += uint64(typ.Size()) 47 48 switch val.Kind() { 49 case reflect.Ptr: 50 if val.IsNil() { 51 break 52 } 53 if refmap[val.Pointer()] { 54 break 55 } 56 57 fallthrough 58 case reflect.Interface: 59 processing = append(processing, val.Elem()) 60 61 case reflect.Struct: 62 sz -= uint64(typ.Size()) 63 for i := 0; i < val.NumField(); i++ { 64 processing = append(processing, val.Field(i)) 65 } 66 67 case reflect.Array: 68 if isNativeType(typ.Elem().Kind()) { 69 break 70 } 71 sz -= uint64(typ.Size()) 72 for i := 0; i < val.Len(); i++ { 73 processing = append(processing, val.Index(i)) 74 } 75 case reflect.Slice: 76 el := typ.Elem() 77 if isNativeType(el.Kind()) { 78 sz += uint64(val.Len()) * uint64(el.Size()) 79 break 80 } 81 for i := 0; i < val.Len(); i++ { 82 processing = append(processing, val.Index(i)) 83 } 84 case reflect.Map: 85 if val.IsNil() { 86 break 87 } 88 kel, vel := typ.Key(), typ.Elem() 89 if isNativeType(kel.Kind()) && isNativeType(vel.Kind()) { 90 sz += uint64(kel.Size()+vel.Size()) * uint64(val.Len()) 91 break 92 } 93 keys := val.MapKeys() 94 for i := 0; i < len(keys); i++ { 95 processing = append(processing, keys[i]) 96 processing = append(processing, val.MapIndex(keys[i])) 97 } 98 case reflect.String: 99 sz += uint64(val.Len()) 100 } 101 } 102 processingPool.Put(processing) 103 return 104 }