Search code examples
goreflectiongo-reflect

How to get size of struct containing data structures in Go?


I'm currently trying to get the size of a complex struct in Go.

I've read solutions that use reflect and unsafe, but neither of these help with structs that contain arrays or maps (or any other field that's a pointer to an underlying data structure).

Example:

type testStruct struct {
    A     int
    B     string
    C     struct{}
    items map[string]string
}

How would I find out the correct byte size of the above if items contains a few values in it?


Solution

  • You can get very close to the amount of memory required by the structure and its content by using the package reflect. You need to iterate over the fields and obtain the size of each field. For example:

    func getSize(v interface{}) int {
        size := int(reflect.TypeOf(v).Size())
        switch reflect.TypeOf(v).Kind() {
        case reflect.Slice:
            s := reflect.ValueOf(v)
            for i := 0; i < s.Len(); i++ {
                size += getSize(s.Index(i).Interface())
            }
        case reflect.Map:
            s := reflect.ValueOf(v)
            keys := s.MapKeys()
            size += int(float64(len(keys)) * 10.79) // approximation from https://golang.org/src/runtime/hashmap.go
            for i := range(keys) {
                size += getSize(keys[i].Interface()) + getSize(s.MapIndex(keys[i]).Interface())
            }
        case reflect.String:
            size += reflect.ValueOf(v).Len()
        case reflect.Struct:
            s := reflect.ValueOf(v)
            for i := 0; i < s.NumField(); i++ {
                if s.Field(i).CanInterface() {
                    size += getSize(s.Field(i).Interface())
                }
            }
        }
        return size
    }
    

    This obtains the size of v using reflect and then, for the supported types in this example (slices, maps, strings, and structs), it computes the memory required by the content stored in them. You would need to add here other types that you need to support.

    There are a few details to work out:

    1. Private fields are not counted.
    2. For structs we are double-counting the basic types.

    For number two, you can filter them out before doing the recursive call when handling structs, you can check the kinds in the documentation for the reflect package.