58

Does anybody know how to get memory size of the variable (int, string, []struct, etc) and print it? Is it possible?

var i int = 1
//I want to get something like this:
fmt.Println("Size of i is: %?", i)
//Also, it would be nice if I could store the value into a string
JasonMArcher
  • 14,195
  • 22
  • 56
  • 52
Timur Fayzrakhmanov
  • 17,967
  • 20
  • 64
  • 95

5 Answers5

76

You can use the unsafe.Sizeof function for this. It returns the size in bytes, occupied by the value you pass into it. Here's a working example:

package main

import "fmt"
import "unsafe"

func main() {
    a := int(123)
    b := int64(123)
    c := "foo"
    d := struct {
        FieldA float32
        FieldB string
    }{0, "bar"}

    fmt.Printf("a: %T, %d\n", a, unsafe.Sizeof(a))
    fmt.Printf("b: %T, %d\n", b, unsafe.Sizeof(b))
    fmt.Printf("c: %T, %d\n", c, unsafe.Sizeof(c))
    fmt.Printf("d: %T, %d\n", d, unsafe.Sizeof(d))
}

Take note that some platforms explicitly disallow the use of unsafe, because it is.. well, unsafe. This used to include AppEngine. Not sure if that is still the case today, but I imagine so.

As @Timur Fayzrakhmanov notes, reflect.TypeOf(variable).Size() will give you the same information. For the reflect package, the same restriction goes as for the unsafe package. I.e.: some platforms may not allow its use.

Tarasovych
  • 2,228
  • 3
  • 19
  • 51
jimt
  • 25,324
  • 8
  • 70
  • 60
  • 4
    What if I have `x := make([][256]byte, 8, 16)` and I want to know the byte size of `x`? `unsafe.Sizeof(x)` will just return 12, no matter how many bytes are allocated. – Hubro Mar 03 '17 at 08:48
  • 4
    @Hubro, the 12 bytes you are seeing is that of the `reflect.SliceHeader` type. Which is what you are creating with that expression. Counting the real size needs some manual work. E.g.: https://play.golang.org/p/o5ejsmWren (very naive proof of concept) – jimt Mar 03 '17 at 14:29
  • 4
    I think this is incorrect, `unsafe.Sizeof` returns the size of the header of slices and strings, which is just a pointer and a length (plus cap for slices). That will be a constant size. The question is about the memory usage of the value. – Seraf Nov 28 '20 at 05:24
19

You can do it with either unsafe.Sizeof(), or reflect.Type.Size()

JimB
  • 104,193
  • 13
  • 262
  • 255
7

The size of a variable can be determined by using unsafe.Sizeof(a). The result will remain the same for a given type (i.e. int, int64, string, struct etc), irrespective of the value it holds. However, for type string, you may be interested in the size of the string that the variable references, and this is determined by using len(a) function on a given string. The following snippet illustrates that size of a variable of type string is always 8 but the length of a string that a variable references can vary:

package main

import "fmt"
import "unsafe"

func main() {
    s1 := "foo"
    s2 := "foobar"

    fmt.Printf("s1 size: %T, %d\n", s1, unsafe.Sizeof(s1))
    fmt.Printf("s2 size: %T, %d\n", s2, unsafe.Sizeof(s2))
    fmt.Printf("s1 len: %T, %d\n", s1, len(s1))
    fmt.Printf("s2 len: %T, %d\n", s2, len(s2))
}

Output:

s1 size: string, 8
s2 size: string, 8
s1 len: string, 3
s2 len: string, 6

The last part of your question is about assigning the length (i.e. an int value) to a string. This can be done by s := strconv.Itoa(i) where i is an int variable and the string returned by the function is assigned to s.

Note: the name of the converter function is Itoa, possibly a short form for Integer to ASCII. Most Golang programmers are likely to misread the function name as Iota.

  • 1
    "size of a variable of type string is always 8". No, the size of the string descriptor is either 8 or 16 bytes. For example, `s1 size: string, 16` and `s2 size: string, 16`. – peterSO Nov 26 '14 at 07:46
  • 1
    "Most Golang programmers are likely to misread the function name [`strconv.Itoa`] as `Iota`." Not likely, "Within a constant declaration, the predeclared identifier [iota](http://golang.org/ref/spec#Iota) represents successive untyped integer constants." – peterSO Nov 26 '14 at 07:50
5

I've written a package which calculates the actual memory size consumed by variable at runtime: https://github.com/DmitriyVTitov/size It has single function, so basic usage is:

fmt.Println(size.Of(varName))

0

unsafe.Sizeof() is the correct solution.

var i int
var u uint
var up uintptr


fmt.Printf("i Type:%T Size:%d\n", i, unsafe.Sizeof(i))
fmt.Printf("u Type:%T Size:%d\n", u, unsafe.Sizeof(u))
fmt.Printf("up Type:%T Size:%d\n", up, unsafe.Sizeof(up))

The int, uint, and uintptr types are usually 32 bits wide on 32-bit systems and 64 bits wide on 64-bit systems. When you need an integer value you should use int unless you have a specific reason to use a sized or unsigned integer type.