Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Go中对象的大小_Go - Fatal编程技术网

Go中对象的大小

Go中对象的大小,go,Go,我正在考虑构建一个基于LRU的缓存机制,该机制能够感知内存消耗,因为在一些搜索之后,我找不到一个现成的机制。缓存项是本机Go对象,可以是基本类型、结构、切片、数组或任何有效组合,但无需递归引用,我们可以为池分配内存使用上限,一旦总内存消耗达到阈值,将触发基于最近使用的最新版本的清理 我知道精确的内存大小计算是不实际的,但我认为粗略的估计可能会有很大帮助。至少它比像在GroupCache中忽略缓存对象的大小那样计算项目数要好 那么,计算/估计给定值使用的字节的正确方法是什么 我不确定两者之间是否有

我正在考虑构建一个基于LRU的缓存机制,该机制能够感知内存消耗,因为在一些搜索之后,我找不到一个现成的机制。缓存项是本机Go对象,可以是基本类型、结构、切片、数组或任何有效组合,但无需递归引用,我们可以为池分配内存使用上限,一旦总内存消耗达到阈值,将触发基于最近使用的最新版本的清理

我知道精确的内存大小计算是不实际的,但我认为粗略的估计可能会有很大帮助。至少它比像在GroupCache中忽略缓存对象的大小那样计算项目数要好


那么,计算/估计给定值使用的字节的正确方法是什么

我不确定两者之间是否有区别,但这里有一个 有两种方法,一种使用反射,另一种使用不安全的包

package main 
import (
    "fmt"
    "reflect"
    "unsafe"
)

type T struct {
    a byte
    b int32
        c [1234]byte
        d float32   
}


func main(){
        var a T
    s1 := reflect.TypeOf(a)
    s2 := unsafe.Sizeof(T{})
    fmt.Printf("reflect.Sizeof(T) = %d, unsafe.Sizeof(T{} = %d)", s1.Size(), s2)
}

我很久以前写过这个函数,它是递归的,没有经过太多的测试,但是它给了你一个如何实现它的想法:

var (
    sliceSize  = uint64(reflect.TypeOf(reflect.SliceHeader{}).Size())
    stringSize = uint64(reflect.TypeOf(reflect.StringHeader{}).Size())
)

func isNativeType(k reflect.Kind) bool {
    switch k {
    case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
        reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
        reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
        return true
    }
    return false
}

func sizeofInternal(val reflect.Value, fromStruct bool, depth int) (sz uint64) {
    if depth++; depth > 1000 {
        panic("sizeOf recursed more than 1000 times.")
    }

    typ := val.Type()

    if !fromStruct {
        sz = uint64(typ.Size())
    }

    switch val.Kind() {
    case reflect.Ptr:
        if val.IsNil() {
            break
        }
        sz += sizeofInternal(val.Elem(), false, depth)

    case reflect.Struct:
        for i := 0; i < val.NumField(); i++ {
            sz += sizeofInternal(val.Field(i), true, depth)
        }

    case reflect.Array:
        if isNativeType(typ.Elem().Kind()) {
            break
        }
        sz = 0
        for i := 0; i < val.Len(); i++ {
            sz += sizeofInternal(val.Index(i), false, depth)
        }
    case reflect.Slice:
        if !fromStruct {
            sz = sliceSize
        }
        el := typ.Elem()
        if isNativeType(el.Kind()) {
            sz += uint64(val.Len()) * uint64(el.Size())
            break
        }
        for i := 0; i < val.Len(); i++ {
            sz += sizeofInternal(val.Index(i), false, depth)
        }
    case reflect.Map:
        if val.IsNil() {
            break
        }
        kel, vel := typ.Key(), typ.Elem()
        if isNativeType(kel.Kind()) && isNativeType(vel.Kind()) {
            sz += uint64(kel.Size()+vel.Size()) * uint64(val.Len())
            break
        }
        keys := val.MapKeys()
        for i := 0; i < len(keys); i++ {
            sz += sizeofInternal(keys[i], false, depth) + sizeofInternal(val.MapIndex(keys[i]), false, depth)
        }
    case reflect.String:
        if !fromStruct {
            sz = stringSize
        }
        sz += uint64(val.Len())
    }
    return
}

// Sizeof returns the estimated memory usage of object(s) not just the size of the type.
// On 64bit Sizeof("test") == 12 (8 = sizeof(StringHeader) + 4 bytes).
func Sizeof(objs ...interface{}) (sz uint64) {
    for i := range objs {
        sz += sizeofInternal(reflect.ValueOf(objs[i]), false, 0)
    }
    return
}
var(
sliceSize=uint64(reflect.TypeOf(reflect.SliceHeader{}).Size())
stringSize=uint64(reflect.TypeOf(reflect.StringHeader{}).Size())
)
func isNativeType(k reflect.Kind)bool{
开关k{
大小写reflect.Int,reflect.Int8,reflect.Int16,reflect.Int32,reflect.Int64,
reflect.Uint,reflect.Uint8,reflect.Uint16,reflect.Uint32,reflect.Uint64,
reflect.Float32、reflect.Float64、reflect.Complex64、reflect.Complex128:
返回真值
}
返回错误
}
func sizeofInternal(val reflect.Value,fromStruct bool,depth int)(sz uint64){
如果深度++;深度>1000{
恐慌(“sizeOf递归超过1000次。”)
}
类型:=值类型()
if!fromStruct{
sz=uint64(典型尺寸()
}
切换值种类(){
案例反映。Ptr:
如果val.IsNil(){
打破
}
sz+=sizeofInternal(val.Elem(),false,depth)
case reflect.Struct:
对于i:=0;i

数学可能有点不对劲

//编辑


修复了数学问题,并将其推到以供将来参考。

这可能有点晚,但可能会有所帮助。Sizeof()将返回大小

package util

import (
    "math/cmplx"
    "reflect"
    "unsafe"
)

var Size []uint64

//Sizeof Function Will Find Approximate Size of Object in Bytes
func Sizeof(i interface{}) (size uint64) {
    size = 0
    sizeof(reflect.ValueOf(i), &size)
    return
}

//sizeof  private function which used to calculate size of object
func sizeof(val reflect.Value, sizeptr *uint64) {
    if val.Kind() >= reflect.Bool && val.Kind() <= reflect.Complex128 {
        (*sizeptr) += Size[val.Kind()]
        return
    }
    switch val.Kind() {
    case reflect.String:
        (*sizeptr) += Size[reflect.String] * uint64(val.Len())
    case reflect.Array:
        /*
            Then iterate through the array and get recursively call the size method.
            If all element hold the same value calculate size for one and multiply it with
            length of array. Wont wonk correctly if the array holds slices or any dynamic
            elements
        */
        for i := 0; i < val.Len(); i++ {
            sizeof(val.Index(i), (sizeptr))
        }

    case reflect.Interface:
        /*
            First we need to get the underlying object of Interface in golang using the Elem()
            And then we need to recursively call this function
        */
        temp := val.Elem()
        sizeof(temp, (sizeptr))

    case reflect.Map:
        for _, key := range val.MapKeys() {
            /*
                get the size of key by calling the size function
            */
            sizeof(key, (sizeptr))

            /*
                get the value pointed by the key and then recursively compute its size
            */
            mapVal := val.MapIndex(key)
            sizeof(mapVal, sizeptr)
        }

    case reflect.Ptr:
        prtVal := val.Elem()
        /*
            If the pointer is invalid or the pointer is nil then return without updating the size
        */
        if !prtVal.IsValid() {
            return
        }

        sizeof(val.Elem(), sizeptr)

    case reflect.Slice:
        for i := 0; i < val.Len(); i++ {
            sizeof(val.Index(i), sizeptr)
        }

    case reflect.Struct:
        /*
            Didn't consider the NumMethod here. Don't this that this is necessary or is it??
            Need to verify this...
        */
        for i := 0; i < val.NumField(); i++ {
            sizeof(val.Field(i), sizeptr)
        }

    case reflect.UnsafePointer:
        /*
            This allows conversion between elements. Dont think this should this is used in calculating
            size
        */
    case reflect.Func:
        // How to handle function pointers
    case reflect.Chan:
        // Don't think this case has to be handled as it will be produced and consumed
    default:
        return
    }
    return
}

func init() {
    Size = make([]uint64, 32)

    bool_val := true
    Size[reflect.Bool] = uint64(unsafe.Sizeof(bool(bool_val)))

    int_val := int(0)
    Size[reflect.Int] = uint64(unsafe.Sizeof(int_val))

    int8_val := int8(0)
    Size[reflect.Int8] = uint64(unsafe.Sizeof(int8_val))

    int16_val := int16(0)
    Size[reflect.Int16] = uint64(unsafe.Sizeof(int16_val))

    int32_val := int32(0)
    Size[reflect.Int32] = uint64(unsafe.Sizeof(int32_val))

    int64_val := int64(0)
    Size[reflect.Int64] = uint64(unsafe.Sizeof(int64_val))

    uint_val := uint(0)
    Size[reflect.Uint] = uint64(unsafe.Sizeof(uint_val))

    uint8_val := uint8(0)
    Size[reflect.Uint8] = uint64(unsafe.Sizeof(uint8_val))

    uint16_val := uint16(0)
    Size[reflect.Uint16] = uint64(unsafe.Sizeof(uint16_val))

    uint32_val := uint32(0)
    Size[reflect.Uint32] = uint64(unsafe.Sizeof(uint32_val))

    uint64_val := uint64(0)
    Size[reflect.Uint64] = uint64(unsafe.Sizeof(uint64_val))

    uintptr_val := uint64(0)
    Size[reflect.Uintptr] = uint64(unsafe.Sizeof(uintptr_val))

    float32_val := float32(0.0)
    Size[reflect.Float32] = uint64(unsafe.Sizeof(float32_val))

    float64_val := float64(0.0)
    Size[reflect.Float64] = uint64(unsafe.Sizeof(float64_val))

    complex64_val := complex64(cmplx.Sqrt(0 + 0i))
    Size[reflect.Complex64] = uint64(unsafe.Sizeof(complex64_val))

    complex128_val := complex128(cmplx.Sqrt(0 + 0i))
    Size[reflect.Complex128] = uint64(unsafe.Sizeof(complex128_val))

    string_val := string("0")
    Size[reflect.String] = uint64(unsafe.Sizeof(string_val))

}
package-util
进口(
“数学/cmplx”
“反映”
“不安全”
)
变量大小[]uint64
//Sizeof函数将查找对象的近似大小(以字节为单位)
func Sizeof(i接口{})(大小uint64){
大小=0
sizeof(反映(i)的值和大小)
返回
}
//sizeof private函数,用于计算对象的大小
func sizeof(值reflect.Value,sizeptr*uint64){

如果val.Kind()>=reflect.Bool&&val.Kind()感谢@nos的快速回复。但是这些方法不能涵盖的一件事是“t{e:“ddddddd”,}”,其中包含一个大小不固定的字段。它对计算的大小没有影响,即使是超长的。是-但您已经说过“但是没有递归引用”-这包括字符串。Sizeof只提供类型的大小。如果成员是指针,指针将按大小计数,而不是指向什么。如果有切片,则相同,只有切片类型,而不是底层数组(如果有),并且只有字符串类型,而不是字符串的内容-字符串很像一个切片。如果您有切片/指针/字符串/映射/通道成员,则必须递归结构的成员列表,例如,还要查找这些成员的长度-这可以通过反射来完成。很抱歉@nos我不清楚。“递归”意味着没有指针指向self或任何子项:)您是否事先知道进入该缓存的所有类型的内容的确切布局,或者结构仅在运行时知道?如果您知道所有不同的布局,您可以计算每个布局的大小,然后对缓存中每种类型的数量运行计数器。您是否可以使用op down方法?@RickyA,因为它可以在堆栈上分配,并且不会显示在那里。@OneOfOne:是的,但是如果你使用一个大结构来保存所有项目,那么它们在堆栈上的可能性就相当低。根据go的说法,在怀疑var作用域时,它似乎更倾向于堆。而且,因为我们没有寻找一个确切的数字,所以这个反射是凝灰岩似乎是一个巨大的开销。哦,顺便说一句,goroutine堆栈的实现感谢@OneOfOne。这应该是我所知的最接近的解决方案。@JasonXu,如果你改进它或enha