首页 > 其他分享 >golang 获得一个结构体的字节大小

golang 获得一个结构体的字节大小

时间:2024-05-06 14:24:56浏览次数:21  
标签:reflect 字节 forSize vl tp golang int 大小 Size

golang 的内存占用是如何构成的呢?

unsafe.SizeOf()

转载:如何在Go中获取变量的内存大小?--CSDN问答

如果传递一个未初始化的变量,unsafe.Sizeof()与reflect.Type.Size()将只返回传递的变量的类型的大小,并不递归地遍历数据结构并增加所指向变量的大小。

切片是一个相对简单的结构体struct:reflect.SliceHeader,因为我们知道切片是引用一个备份的数组(或字符串——byte数组),我们可以简单地手动计算它的大小:

sliceint := make([]int32, 1000) //指向元素类型为int32的1000个元素的数组的切片
fmt.Println("Size of []int32:", unsafe.Sizeof(sliceint)) //24
fmt.Println("Size of [1000]int32:", unsafe.Sizeof([1000]int32{})) //4000
fmt.Println("Real size of s:", unsafe.Sizeof(sliceint)+unsafe.Sizeof([1000]int32{})) //4024
输出:

Size of []int32: 24
Size of [1000]int32: 4000
Real size of s: 4024
也就是创建一个相同类型的初始化过的切片,并


func GetGoVarSize(val any) (sumSize int) {
	vl := reflect.ValueOf(val)
	tp := reflect.TypeOf(val)
	//tp.Size() + vl.Kind()
	switch vl.Kind() {
	case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8,
		reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64, reflect.Complex64,
		reflect.Complex128:
		return int(tp.Size()) //unsafe.Sizeof(val)
	case reflect.Map:
		forSize := int(tp.Size())
		for _, i := range vl.MapKeys() {
			forSize += GetGoVarSize(i.Interface()) + GetGoVarSize(vl.MapIndex(i).Interface())
		}
		return forSize
	case reflect.Array, reflect.Slice:
		forSize := int(tp.Size())
		for i := 0; i < vl.Len(); i++ {
			forSize += GetGoVarSize(vl.Index(i).Interface())
		}
		return forSize
		//return int(tp.Size()) + vl.Len()*GetGoVarSize(vl.Elem().Interface())//array and slice , not have Elem()
	case reflect.Chan:
		//请注意,尝试获取channel元素类型的操作(即varType.Elem())是不允许的,因为这将导致运行时的panic。在Go中,你不能通过反射来获取channel的元素类型。
		forSize := int(tp.Size())
		for i := 0; i < vl.Len(); i++ {
			forSize += 0
		}
		return forSize
	case reflect.Func:
		return int(tp.Size())
	case reflect.Interface:
		fallthrough
	case reflect.Pointer:
		forSize := int(tp.Size())
		if vl.IsNil() {
			return forSize
		}
		return forSize + GetGoVarSize(vl.Elem().Interface())
	case reflect.String:
		forSize := int(tp.Size())
		for i := 0; i < vl.Len(); i++ {
			forSize += GetGoVarSize(vl.Index(i).Interface())
		}
		return forSize
	case reflect.Struct:
		forSize := int(tp.Size())
		for i := 0; i < vl.NumField(); i++ {
			tpField := tp.Field(i)
			vlField := vl.Field(i)
			if tp.Name() == "Time" && tp.PkgPath() == "time" {
				_ = &time.Time{}
				//forSize += 8*2 + GetGoVarSize(time.Location{})
				//forSize += 8*2 + (16 + 5) + (24 + (8 + 3) + (8 + 1)) + (24 + (8 + 1 + 2)) + (16 + 0) + 8 + 8 + (8 + (3 + 8 + 1))
				forSize += 24 //time.Time{} 基本都是空数据,就用这个; 有 time.Local的才会用到上面的这个.
				continue
			}
			if !tpField.IsExported() {
				s := int(vlField.Type().Size()) //int(tpField.Type.Size())
				forSize += s
				log.Printf("Struct (%T)'s field(%v) not IsExported() string:%v, theSize=%v tp=%v vl=%v\n", val, i, vlField.String(), s, tpField, vlField)

				//TODO 不可导出字段,应该可以通过 unsafe 获取数据的. 不处理这个问题,无法获得真实的大小的.
				//var tp = reflect.New(tpField.Type)
				//tp.SetPointer(unsafe.Pointer(vlField.UnsafePointer()))
				//forSize += GetGoVarSize(tp.Interface())

				continue
			}
			if !vlField.CanInterface() {
				s := int(vlField.Type().Size())
				forSize += s
				log.Printf("Struct (%T)'s field(%v) cannot string:%v theSize use :%v\n", val, i, vlField.String(), s)
				continue
			}

			switch vlField.Kind() {
			case reflect.Chan, reflect.Func, reflect.Map, reflect.Pointer, reflect.UnsafePointer,
				reflect.Interface, reflect.Slice:
				if vlField.IsNil() {
					forSize += int(vlField.Type().Size())
					continue
				}
			}
			forSize += GetGoVarSize(vlField.Interface())
		}
		return forSize
	case reflect.UnsafePointer:
		forSize := int(tp.Size())
		return forSize
	default:
		//return 0
		panic(fmt.Errorf(" %T Not support Kind %v", val, vl.Kind()))
	}
	return 0
}


标签:reflect,字节,forSize,vl,tp,golang,int,大小,Size
From: https://www.cnblogs.com/ayanmw/p/18174933

相关文章

  • .net 6 栈的大小是多少
    .NET6中线程栈的默认大小并没有在官方文档中明确给出一个具体的数值,因为它可以根据操作系统、体系结构(32位或64位)以及线程启动时的特定条件有所不同。一般来说,对于托管代码,.NET中的线程栈大小默认是相对较大的,通常在1MB到1MB范围内,具体大小可能会根据操作系统的默认设置和可用......
  • 用Golang做一个永久阻塞,有哪些小技巧 ?
    用Golang做一个永久阻塞,有哪些小技巧?磊丰 Go语言圈 2024-05-0608:30 广东 听全文Go语言圈Go语言开发者的学习好助手,分享Go语言知识,技术技巧,学习与交流Go语言开发经验,互动才有助于技术的提升,每天5分钟,助你GO语言技术快乐成长159篇原创内容公众号......
  • 为什么我要使得GOLang重写SAAS(软件即服务)服务端
    引言“道”在中国哲学中,是一个重要的概念,表示“终极真理”。“道”这一概念,不单为哲学流派诸子百家所重视,也被宗教流派道教等所使用。大道至简的意思就是大道理是极其简单的,简单到一两句话就能说明白。所谓“真传一句话,假传万卷书”。正文在开启独立创作之路之前,我主要用不用......
  • Golang:go-humanize将文件大小转换成Kb、Mb、Gb适合人类阅读的单位
    Golang:go-humanize将文件大小转换成Kb、Mb、Gb适合人类阅读的单位原创 吃个大西瓜 CodingBigTree 2024-05-0408:30 云南​最近去了昆明的教场中路体验了满屏蓝花楹,感受到了梦幻般的世界,随手拍了一张图,分享给大家,有时间可以去一趟,体验一次,顺便说一下,美女很多喔 ......
  • golang 官方代码 汇总
    go1.22.2-- 序章golang官网的代码汇总,汇总到一起,方便查阅。 注,如有侵权,请通知我处理......
  • golang初学:交叉编译
    goversiongo1.22.1windows/amd64Windows11+amd64x86_64x86_64GNU/Linux--- 序章golang支持跨平台,支持的方式是在一个平台编译其它平台的可执行程序。本文介绍Windows11(开发主机)上编译Linux(目标主机)上的可执行程序。 #gobuild 开发主机和目标......
  • 卷积核大小选择、网络层数问题
    CNN网络结构设计的观点:每一层卷积有多少filters,以及一共有多少层卷积,这些暂时没有理论支撑。一般都是靠感觉去设置几组候选值,然后通过实验挑选出其中的最佳值。每一层卷积的filters数和网络的总卷积层数,构成了一个巨大的超参集合。一来没有理论去求解这个超参集合里的最优,二来......
  • 禅道文件大小限制-nginx 调整
    今天在使用禅道上传文件的时候发现了一个问题,我可以上传几十k的文件,但是上传不了大几M的文件,当文件过大的时候,一直卡在哪里,上传不了(使用的是开源版9.8.1)。在官方文档中可以看到需要调整php.ini中的post_max_size和upload_max_filesize值,然后重启apache即可生效:  #cd/......
  • 【发现一个小问题】golang http client: 配置了Client 对象的 Timeout 就会导致 conte
    作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢!cnblogs博客zhihuGithub公众号:一本正经的瞎扯我这样初始化了客户端:varclient=http.Client{Timeout:time.Duration(1000)*time.Millisecond,}然后在request创建过程中使用了context的timeout机制:tim......
  • 转载golang中net/http包用法
    转自:https://studygolang.com/articles/55151.前言http包包含http客户端和服务端的实现,利用Get,Head,Post,以及PostForm实现HTTP或者HTTPS的请求.2.本文分析内容安排函数结构3.函数3.1服务端函数funcHandle(patternstring,handlerHandler)将handler按照指定的......