FAQ
I'm not sure, but is this intended behavior? In the following code, calling
foo on bar causes an allocation, while calling foo on baz does not. I
assume this is because bar is not an interface value, and thus, the runtime
needs to allocate a GoInterface struct for bar. Is there a reason that this
is not allocated on the stack?

var bar string = "hello"
var baz interface{} = "hello"

func foo(val interface{}) {}

func main() {
ms1, ms2 := new(runtime.MemStats), new(runtime.MemStats)

runtime.GC()
runtime.ReadMemStats(ms1)
for i := 0; i < 1000; i++ {
foo(bar)
}
runtime.ReadMemStats(ms2)
fmt.Println("NumMallocs:", ms2.Mallocs-ms1.Mallocs) // 1000 mallocs
fmt.Println("TotalAlloc:", ms2.TotalAlloc-ms1.TotalAlloc)

runtime.GC()
runtime.ReadMemStats(ms1)
for i := 0; i < 1000; i++ {
foo(baz)
}
runtime.ReadMemStats(ms2)
fmt.Println("NumMallocs:", ms2.Mallocs-ms1.Mallocs) // 0 mallocs
fmt.Println("TotalAlloc:", ms2.TotalAlloc-ms1.TotalAlloc)
}

Playground <https://play.golang.org/p/0DI_hVrebj>

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Search Discussions

  • Roberto Zanotto at Jul 10, 2015 at 1:46 am
    It's interesting. According to blog
    <http://blog.golang.org/laws-of-reflection> posts
    <http://research.swtch.com/interfaces>, an interface is represented as a
    pair (pointer to concrete value, type descriptor) and should be allocated
    "on the stack". The interface should contain a pointer to bar, but the
    interface itself should not be boxed on the heap. I'm wondering what's
    happening here. I'm pretty sure I'm missing something, as it always turns
    out :)
    On Friday, July 10, 2015 at 2:53:29 AM UTC+2, thebroke...@gmail.com wrote:

    I'm not sure, but is this intended behavior? In the following code,
    calling foo on bar causes an allocation, while calling foo on baz does not.
    I assume this is because bar is not an interface value, and thus, the
    runtime needs to allocate a GoInterface struct for bar. Is there a reason
    that this is not allocated on the stack?

    var bar string = "hello"
    var baz interface{} = "hello"

    func foo(val interface{}) {}

    func main() {
    ms1, ms2 := new(runtime.MemStats), new(runtime.MemStats)

    runtime.GC()
    runtime.ReadMemStats(ms1)
    for i := 0; i < 1000; i++ {
    foo(bar)
    }
    runtime.ReadMemStats(ms2)
    fmt.Println("NumMallocs:", ms2.Mallocs-ms1.Mallocs) // 1000 mallocs
    fmt.Println("TotalAlloc:", ms2.TotalAlloc-ms1.TotalAlloc)

    runtime.GC()
    runtime.ReadMemStats(ms1)
    for i := 0; i < 1000; i++ {
    foo(baz)
    }
    runtime.ReadMemStats(ms2)
    fmt.Println("NumMallocs:", ms2.Mallocs-ms1.Mallocs) // 0 mallocs
    fmt.Println("TotalAlloc:", ms2.TotalAlloc-ms1.TotalAlloc)
    }

    Playground <https://play.golang.org/p/0DI_hVrebj>
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Roberto Zanotto at Jul 10, 2015 at 2:20 am
    Playing a bit on the playground helped me figure out something. If you
    change the type of bar (here with [32]byte
    <https://play.golang.org/p/_QJWcAiz26>) it's allocating exactly the amount
    of memory needed to store 1000 of those variables. So it looks like it's
    not storing the interfaces on the heap, but it's re-allocating bar when
    assigning it to interface{}. Still trying to understand why...
    On Friday, July 10, 2015 at 2:53:29 AM UTC+2, thebroke...@gmail.com wrote:

    I'm not sure, but is this intended behavior? In the following code,
    calling foo on bar causes an allocation, while calling foo on baz does not.
    I assume this is because bar is not an interface value, and thus, the
    runtime needs to allocate a GoInterface struct for bar. Is there a reason
    that this is not allocated on the stack?

    var bar string = "hello"
    var baz interface{} = "hello"

    func foo(val interface{}) {}

    func main() {
    ms1, ms2 := new(runtime.MemStats), new(runtime.MemStats)

    runtime.GC()
    runtime.ReadMemStats(ms1)
    for i := 0; i < 1000; i++ {
    foo(bar)
    }
    runtime.ReadMemStats(ms2)
    fmt.Println("NumMallocs:", ms2.Mallocs-ms1.Mallocs) // 1000 mallocs
    fmt.Println("TotalAlloc:", ms2.TotalAlloc-ms1.TotalAlloc)

    runtime.GC()
    runtime.ReadMemStats(ms1)
    for i := 0; i < 1000; i++ {
    foo(baz)
    }
    runtime.ReadMemStats(ms2)
    fmt.Println("NumMallocs:", ms2.Mallocs-ms1.Mallocs) // 0 mallocs
    fmt.Println("TotalAlloc:", ms2.TotalAlloc-ms1.TotalAlloc)
    }

    Playground <https://play.golang.org/p/0DI_hVrebj>
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Tim K at Jul 10, 2015 at 2:27 am
    Because it makes a copy of the data and it puts a pointer to the data copy
    in the interface. If you are instead calling foo(&bar) you will see 0
    mallocs.

    Now why it does it for the string, I'm not sure, strings are immutable so
    you would think it could be optimized to just have a pointer to an interned
    string. Perhaps it's just not yet optimized or I'm missing something else
    as I'm very new to Go.

    On Thursday, July 9, 2015 at 7:20:35 PM UTC-7, Roberto Zanotto wrote:

    Playing a bit on the playground helped me figure out something. If you
    change the type of bar (here with [32]byte
    <https://play.golang.org/p/_QJWcAiz26>) it's allocating exactly the
    amount of memory needed to store 1000 of those variables. So it looks like
    it's not storing the interfaces on the heap, but it's re-allocating bar
    when assigning it to interface{}. Still trying to understand why...
    On Friday, July 10, 2015 at 2:53:29 AM UTC+2, thebroke...@gmail.com wrote:

    I'm not sure, but is this intended behavior? In the following code,
    calling foo on bar causes an allocation, while calling foo on baz does not.
    I assume this is because bar is not an interface value, and thus, the
    runtime needs to allocate a GoInterface struct for bar. Is there a reason
    that this is not allocated on the stack?

    var bar string = "hello"
    var baz interface{} = "hello"

    func foo(val interface{}) {}

    func main() {
    ms1, ms2 := new(runtime.MemStats), new(runtime.MemStats)

    runtime.GC()
    runtime.ReadMemStats(ms1)
    for i := 0; i < 1000; i++ {
    foo(bar)
    }
    runtime.ReadMemStats(ms2)
    fmt.Println("NumMallocs:", ms2.Mallocs-ms1.Mallocs) // 1000 mallocs
    fmt.Println("TotalAlloc:", ms2.TotalAlloc-ms1.TotalAlloc)

    runtime.GC()
    runtime.ReadMemStats(ms1)
    for i := 0; i < 1000; i++ {
    foo(baz)
    }
    runtime.ReadMemStats(ms2)
    fmt.Println("NumMallocs:", ms2.Mallocs-ms1.Mallocs) // 0 mallocs
    fmt.Println("TotalAlloc:", ms2.TotalAlloc-ms1.TotalAlloc)
    }

    Playground <https://play.golang.org/p/0DI_hVrebj>
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Roberto Zanotto at Jul 10, 2015 at 2:56 am
    I didn't know that converting to interface{} a non-pointer variable would
    make a copy and then put the pointer into the interface, while taking the
    pointer before the conversion avoids the copy (makes sense). Apparently
    there are too many things I don't know about Go.
    As for strings, it doesn't make a copy of the whole string content, it just
    copies the couple of words that the string variable takes (those "on the
    stack").
    On Friday, July 10, 2015 at 4:27:13 AM UTC+2, Tim K wrote:

    Because it makes a copy of the data and it puts a pointer to the data copy
    in the interface. If you are instead calling foo(&bar) you will see 0
    mallocs.

    Now why it does it for the string, I'm not sure, strings are immutable so
    you would think it could be optimized to just have a pointer to an interned
    string. Perhaps it's just not yet optimized or I'm missing something else
    as I'm very new to Go.

    On Thursday, July 9, 2015 at 7:20:35 PM UTC-7, Roberto Zanotto wrote:

    Playing a bit on the playground helped me figure out something. If you
    change the type of bar (here with [32]byte
    <https://play.golang.org/p/_QJWcAiz26>) it's allocating exactly the
    amount of memory needed to store 1000 of those variables. So it looks like
    it's not storing the interfaces on the heap, but it's re-allocating bar
    when assigning it to interface{}. Still trying to understand why...

    On Friday, July 10, 2015 at 2:53:29 AM UTC+2, thebroke...@gmail.com
    wrote:
    I'm not sure, but is this intended behavior? In the following code,
    calling foo on bar causes an allocation, while calling foo on baz does not.
    I assume this is because bar is not an interface value, and thus, the
    runtime needs to allocate a GoInterface struct for bar. Is there a reason
    that this is not allocated on the stack?

    var bar string = "hello"
    var baz interface{} = "hello"

    func foo(val interface{}) {}

    func main() {
    ms1, ms2 := new(runtime.MemStats), new(runtime.MemStats)

    runtime.GC()
    runtime.ReadMemStats(ms1)
    for i := 0; i < 1000; i++ {
    foo(bar)
    }
    runtime.ReadMemStats(ms2)
    fmt.Println("NumMallocs:", ms2.Mallocs-ms1.Mallocs) // 1000 mallocs
    fmt.Println("TotalAlloc:", ms2.TotalAlloc-ms1.TotalAlloc)

    runtime.GC()
    runtime.ReadMemStats(ms1)
    for i := 0; i < 1000; i++ {
    foo(baz)
    }
    runtime.ReadMemStats(ms2)
    fmt.Println("NumMallocs:", ms2.Mallocs-ms1.Mallocs) // 0 mallocs
    fmt.Println("TotalAlloc:", ms2.TotalAlloc-ms1.TotalAlloc)
    }

    Playground <https://play.golang.org/p/0DI_hVrebj>
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Tim K at Jul 10, 2015 at 3:02 am
    It has to make a copy, otherwise data would be shared between a struct
    value and the interface value, take a look at this:
    https://play.golang.org/p/qXQ3KDZ7JN

    And yes, you are right, the strings are optimized, I just didn't pay enough
    attention to the allocated memory, if you use longer strings the same
    amount of memory is being allocated, so the size of the string doesn't
    matter.

    On Thursday, July 9, 2015 at 7:56:16 PM UTC-7, Roberto Zanotto wrote:

    I didn't know that converting to interface{} a non-pointer variable would
    make a copy and then put the pointer into the interface, while taking the
    pointer before the conversion avoids the copy (makes sense). Apparently
    there are too many things I don't know about Go.
    As for strings, it doesn't make a copy of the whole string content, it
    just copies the couple of words that the string variable takes (those "on
    the stack").
    On Friday, July 10, 2015 at 4:27:13 AM UTC+2, Tim K wrote:

    Because it makes a copy of the data and it puts a pointer to the data
    copy in the interface. If you are instead calling foo(&bar) you will see 0
    mallocs.

    Now why it does it for the string, I'm not sure, strings are immutable so
    you would think it could be optimized to just have a pointer to an interned
    string. Perhaps it's just not yet optimized or I'm missing something else
    as I'm very new to Go.

    On Thursday, July 9, 2015 at 7:20:35 PM UTC-7, Roberto Zanotto wrote:

    Playing a bit on the playground helped me figure out something. If you
    change the type of bar (here with [32]byte
    <https://play.golang.org/p/_QJWcAiz26>) it's allocating exactly the
    amount of memory needed to store 1000 of those variables. So it looks like
    it's not storing the interfaces on the heap, but it's re-allocating bar
    when assigning it to interface{}. Still trying to understand why...

    On Friday, July 10, 2015 at 2:53:29 AM UTC+2, thebroke...@gmail.com
    wrote:
    I'm not sure, but is this intended behavior? In the following code,
    calling foo on bar causes an allocation, while calling foo on baz does not.
    I assume this is because bar is not an interface value, and thus, the
    runtime needs to allocate a GoInterface struct for bar. Is there a reason
    that this is not allocated on the stack?

    var bar string = "hello"
    var baz interface{} = "hello"

    func foo(val interface{}) {}

    func main() {
    ms1, ms2 := new(runtime.MemStats), new(runtime.MemStats)

    runtime.GC()
    runtime.ReadMemStats(ms1)
    for i := 0; i < 1000; i++ {
    foo(bar)
    }
    runtime.ReadMemStats(ms2)
    fmt.Println("NumMallocs:", ms2.Mallocs-ms1.Mallocs) // 1000 mallocs
    fmt.Println("TotalAlloc:", ms2.TotalAlloc-ms1.TotalAlloc)

    runtime.GC()
    runtime.ReadMemStats(ms1)
    for i := 0; i < 1000; i++ {
    foo(baz)
    }
    runtime.ReadMemStats(ms2)
    fmt.Println("NumMallocs:", ms2.Mallocs-ms1.Mallocs) // 0 mallocs
    fmt.Println("TotalAlloc:", ms2.TotalAlloc-ms1.TotalAlloc)
    }

    Playground <https://play.golang.org/p/0DI_hVrebj>
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Xingtao zhao at Jul 10, 2015 at 4:13 am
    string takes two words, one for pointer, one for Len. so every time it will allocate these two words on heap and then setup interface point to these two words.

    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Tim K at Jul 10, 2015 at 4:36 am
    Indeed. Tried it on 32-bit and 64-bit and it makes sense now. Thanks.
    On Thursday, July 9, 2015 at 9:13:41 PM UTC-7, xingtao zhao wrote:

    string takes two words, one for pointer, one for Len. so every time it
    will allocate these two words on heap and then setup interface point to
    these two words.
    --
    You received this message because you are subscribed to the Google Groups "golang-nuts" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupgolang-nuts @
categoriesgo
postedJul 10, '15 at 12:53a
activeJul 10, '15 at 4:36a
posts8
users4
websitegolang.org

People

Translate

site design / logo © 2021 Grokbase