Cannot benchmark (actual size of int) due to compiler optimization - please help

I want to figure out exactly how much memory gets allocated when I create a new int variable (a := 3).

I could not come up with some function that returns an int, so that I benchmark it and see how much memory it used - because compiler always inlines that function.

Here is what I have come up with so far:
type IntField struct {
payload int
}

func getInt() IntField {
    return IntField{payload: 3}
}

func BenchmarkInt(b *testing.B) {
    for i := 0; i < b.N; i++ {
        b := getInt()
        b.payload = 4
    }
}

The benchmark result is:
BenchmarkInt-8 2000000000 0.29 ns/op 0 B/op 0 allocs/op

So it still does not allocate anything. Please give me ideas on how can I get the compiler to not optimize, thus get a simple function that actually allocates an int, so I see exactly how much memory an int requires.

Also, do not talk to me about unsafe.Sizeof(), as I believe the Golang runtime may actually add some overhead/extra memory even for a simple int variable. How can I check this to get proof either way ?

Come on people, any ideas ?

As you’ve discovered “it depends”. It may get inlined. It may live in a register only.

Why do you believe that? The documentation for Sizeof() even says specifically that it “returns the size in bytes of a hypothetical variable v as if v was declared via var v = x” which is your question.

1 Like

Hi @calmh,

I know it may sound a bit paranoid on my behalf, but I am thinking hwo would I implement the Golang runtime, and I sure could not manage with just 8 bytes for an int: I would at least need a pointer to something that describes its data type and its methods. Maybe also another int where I would store how many active pointers are pointing to it.

What was your idea about converitng to an interface - so as it does not get inlined but forced allocation ? It seems oyu edited your answer.

This is why I am skeptical of Sizeof(). Thx for your reply !

My edited answer was wrong. :slight_smile: A better way is to grab a pointer and store it in a global variable. This forces an allocation:

func getInt() *int {
	return new(int)
}

var g *int

func BenchmarkInt(b *testing.B) {
	for i := 0; i < b.N; i++ {
		g = getInt()
	}
}
$ go test -bench . -benchmem
goos: darwin
goarch: amd64
BenchmarkInt-8   	98839060	        11.2 ns/op	       8 B/op	       1 allocs/op
PASS

Note that this is a trick to fool the compiler. It does not mean that using an int will in general be an eight byte allocation. In general it will be zero allocations as part of your stack or in a register, as in your first attempts.

In short, you should not worry about this. There is plenty of other stuff you can worry about instead when writing code. The size of an int is not one of them.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.