【问题标题】:How to get memory size of variable?如何获取变量的内存大小?
【发布时间】:2015-01-14 13:04:32
【问题描述】:

有人知道如何获取变量的内存大小(intstring[]struct 等)并打印出来吗?有可能吗?

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

【问题讨论】:

  • reflect.TypeOf(i).Size()

标签: memory-management go runtime


【解决方案1】:

您可以使用unsafe.Sizeof()reflect.Type.Size() 来完成此操作

【讨论】:

    【解决方案2】:

    您可以为此使用unsafe.Sizeof 函数。 它返回以字节为单位的大小,由您传递给它的值占用。 这里是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))
    }
    

    请注意,某些平台明确禁止使用 unsafe,因为它是……嗯,不安全的。这曾经包括 AppEngine。不确定今天是否仍然如此,但我想是的。

    正如@Timur Fayzrakhmanov 所说,reflect.TypeOf(variable).Size() 将为您提供相同的信息。对于reflect 包,与unsafe 包相同的限制。即:某些平台可能不允许使用它。

    【讨论】:

    • 如果我有x := make([][256]byte, 8, 16) 并且我想知道x 的字节大小怎么办? unsafe.Sizeof(x) 只会返回 12,无论分配多少字节。
    • @Hubro,你看到的 12 个字节是 reflect.SliceHeader 类型的。这就是您使用该表达式创建的内容。计算实际尺寸需要一些手工工作。例如:play.golang.org/p/o5ejsmWren(非常幼稚的概念证明)
    • 我认为这是不正确的,unsafe.Sizeof 返回切片和字符串的标头的大小,它只是一个指针和一个长度(加上切片的上限)。那将是一个恒定的大小。问题是关于值的内存使用情况。
    【解决方案3】:

    变量的大小可以通过使用unsafe.Sizeof(a) 来确定。对于给定类型(即intint64stringstruct 等),结果将保持不变,而与它所持有的值无关。但是,对于类型string,您可能对变量引用的字符串的大小感兴趣,这是通过对给定字符串使用len(a) 函数来确定的。下面的 sn-p 说明了 string 类型的变量的大小始终为 8,但变量引用的字符串的长度可以变化:

    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))
    }
    

    输出:

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

    您问题的最后一部分是关于将长度(即int 值)分配给string。这可以通过s := strconv.Itoa(i) 完成,其中iint 变量,函数返回的string 被分配给s

    注意:转换器函数的名称是Itoa,可能是整数到ASCII的缩写形式。大多数 Golang 程序员很可能将函数名误读为Iota

    【讨论】:

    • "字符串类型变量的大小始终为 8"。不,字符串描述符的大小是 8 或 16 个字节。例如,s1 size: string, 16s2 size: string, 16
    • "大多数 Golang 程序员很可能将函数名 [strconv.Itoa] 误读为 Iota。"不太可能,“在常量声明中,预先声明的标识符 iota 表示连续的无类型整数常量。”
    【解决方案4】:

    unsafe.Sizeof() 是正确的解决方案。

    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))
    

    int、uint 和 uintptr 类型在 32 位系统上通常为 32 位宽,在 64 位系统上通常为 64 位宽。当你需要一个整数值时,你应该使用 int,除非你有特定的理由使用一个大小或无符号的整数类型。

    【讨论】:

      【解决方案5】:

      我编写了一个包,它计算变量在运行时消耗的实际内存大小:https://github.com/DmitriyVTitov/size 它功能单一,所以基本用法是:

      fmt.Println(size.Of(varName))

      【讨论】:

        猜你喜欢
        • 2017-10-30
        • 2020-02-18
        • 1970-01-01
        • 1970-01-01
        • 2014-08-21
        • 2015-04-28
        • 2011-03-18
        • 1970-01-01
        相关资源
        最近更新 更多