在学习 go 语言项目时,遇到这样一个问题:
通过struct结构体作为一个model,数据绑定等操作都是返回一个结构体指针,那么返回一个结构体变量,或者返回一个结构体指针,他们的区别是什么?
因为二者都可以让我们生成我们所需要的结构体,那为什么还要去使用返回结构体指针呢?
对于此疑问,我做了如下实验
// TableFile : 文件表结构体
type TableFile struct {
FileHash string
FileName string
FileSize string
FileAddr string
}
// GetFileMeta1 从mysql获取文件元信息
func GetFileMeta1(filehash1 string) *TableFile {
tfile1 := TableFile{FileHash: filehash1}
fmt.Printf("GetFileMeta1函数内:%p\n", &tfile1)
return &tfile1
}
// GetFileMeta2 从mysql获取文件元信息
func GetFileMeta2(filehash1 string) TableFile {
tfile2 := TableFile{FileHash: filehash1}
fmt.Printf("GetFileMeta2函数内:%p\n", &tfile2)
return tfile2
}
// GetFileMeta3 从mysql获取文件元信息
func GetFileMeta3(filehash1 string) (tfile3 TableFile) {
tfile3 = TableFile{FileHash: filehash1}
fmt.Printf("GetFileMeta3函数内:%p\n", &tfile3)
return
}
func main() {
t1 := GetFileMeta1("1111")
fmt.Printf("GetFileMeta1 函数外%p\n", t1)
t2 := GetFileMeta2("1111")
fmt.Printf("GetFileMeta2 函数外%p\n", &t2)
t3 := GetFileMeta3("1111")
fmt.Printf("GetFileMeta3 函数外%p\n", &t3)
}
//GetFileMeta1函数内:0xc00005a040
//GetFileMeta1 函数外0xc00005a040
//GetFileMeta2函数内:0xc00005a0c0
//GetFileMeta2 函数外0xc00005a080
//GetFileMeta3函数内:0xc00005a140
//GetFileMeta3 函数外0xc00005a100
这里可以发现:
- 使用指针结构体只分配了一次内存
- 使用结构体值却分配了两次
由于go是值拷贝模式,指针拷贝地址,没有分配多余内存;值拷贝数值,新的变量会重新分配地址给数值。
这一点了解了,可是我仍然不知道指针的性能提升在那里,虽然指针只分配了一次地址空间,可是该空间会分配在堆上发生内存逃逸,影响程序性能;
值空间虽然分配了两次空间,但函数内变量空间分配在栈上,函数结束,系统内核会自动销毁,不影响性能,?难道是多次分配调度内存空间,影响更大?
返回结构体值与结构体指针性能问题:
传值 VS 传指针: 传值会拷贝整个对象,而传指针只会拷贝指针地址,指向的对象是同一个。传指针可以减少值的拷贝,但是会导致内存分配逃逸到堆中,增加垃圾回收(GC)的负担。在对象频繁创建和删除的场景下,传递指针导致的 GC 开销可能会严重影响性能。
一般情况下,对于需要修改原对象值,或占用内存比较大的结构体,选择传指针。对于只读的占用内存较小的结构体,直接传值能够获得更好的性能