github.com/lbryio/lbcd@v0.22.119/mempool/memusage.go (about) 1 // Copyright (c) 2013-2016 The btcsuite developers 2 // Use of this source code is governed by an ISC 3 // license that can be found in the LICENSE file. 4 5 package mempool 6 7 import ( 8 "fmt" 9 "reflect" 10 ) 11 12 var ( 13 dynamicMemUsageAssert = false 14 dynamicMemUsageDebug = false 15 dynamicMemUsageMaxDepth = 10 16 ) 17 18 func dynamicMemUsage(v reflect.Value) uintptr { 19 return dynamicMemUsageCrawl(v, 0) 20 } 21 22 func dynamicMemUsageCrawl(v reflect.Value, depth int) uintptr { 23 t := v.Type() 24 bytes := t.Size() 25 if dynamicMemUsageDebug { 26 println("[", depth, "]", t.Kind().String(), "(", t.String(), ") ->", t.Size()) 27 } 28 29 if depth >= dynamicMemUsageMaxDepth { 30 if dynamicMemUsageAssert { 31 panic("crawl reached maximum depth") 32 } 33 return bytes 34 } 35 36 // For complex types, we need to peek inside slices/arrays/structs and chase pointers. 37 switch t.Kind() { 38 case reflect.Pointer, reflect.Interface: 39 if !v.IsNil() { 40 bytes += dynamicMemUsageCrawl(v.Elem(), depth+1) 41 } 42 case reflect.Array, reflect.Slice: 43 for j := 0; j < v.Len(); j++ { 44 vi := v.Index(j) 45 k := vi.Type().Kind() 46 if dynamicMemUsageDebug { 47 println("[", depth, "] index:", j, "kind:", k.String()) 48 } 49 elemBytes := uintptr(0) 50 if t.Kind() == reflect.Array { 51 if (k == reflect.Pointer || k == reflect.Interface) && !vi.IsNil() { 52 elemBytes += dynamicMemUsageCrawl(vi.Elem(), depth+1) 53 } 54 } else { // slice 55 elemBytes += dynamicMemUsageCrawl(vi, depth+1) 56 } 57 if k == reflect.Uint8 { 58 // short circuit for byte slice/array 59 bytes += elemBytes * uintptr(v.Len()) 60 if dynamicMemUsageDebug { 61 println("...", v.Len(), "elements") 62 } 63 break 64 } 65 bytes += elemBytes 66 } 67 case reflect.Struct: 68 for _, f := range reflect.VisibleFields(t) { 69 vf := v.FieldByIndex(f.Index) 70 k := vf.Type().Kind() 71 if dynamicMemUsageDebug { 72 println("[", depth, "] field:", f.Name, "kind:", k.String()) 73 } 74 if (k == reflect.Pointer || k == reflect.Interface) && !vf.IsNil() { 75 bytes += dynamicMemUsageCrawl(vf.Elem(), depth+1) 76 } else if k == reflect.Array || k == reflect.Slice { 77 bytes -= vf.Type().Size() 78 bytes += dynamicMemUsageCrawl(vf, depth+1) 79 } 80 } 81 case reflect.Uint8: 82 default: 83 if dynamicMemUsageAssert { 84 panic(fmt.Sprintf("unsupported kind: %v", t.Kind())) 85 } 86 } 87 88 return bytes 89 }