传指针不自动省内存,小类型(如int、string)传指针可能更费内存;仅当传递大结构体、大数组或需修改原值时,传指针才大概率减少拷贝。

Go 中传递指针并不自动节省内存,是否省内存取决于你传的是什么类型、有多大、以及是否真的避免了复制。
什么时候传指针反而更费内存?
小基础类型(如 int、bool、string)传指针通常不省内存,还可能更糟:
-
int在 64 位系统上占 8 字节,而*int也是 8 字节指针 —— 大小没变,但多了间接寻址开销 -
string本身是 16 字节结构体(2 个 uint64:指向底层数组的指针 + len),传*string是 8 字节指针,但你要先在堆或栈上分配一个 string 的副本再取地址,实际可能多一次分配 - 编译器可能对值传递做逃逸分析优化,而显式取地址(
&x)反而强制变量逃逸到堆,增加 GC 压力
真正能省内存的场景
只在以下情况传指针才大概率减少内存拷贝:
- 结构体较大(比如字段总和 ≥ 32 字节),且函数内部不修改它(否则考虑用
const语义,但 Go 没 const 参数,只能靠约定) - 你需要函数修改原始值(比如初始化一个大 slice 或 map 字段),这时必须传指针,否则值拷贝后修改无效
- 类型包含大数组(如
[1024]byte)或嵌套大结构体,值传递会完整复制整个内存块
例如:
立即学习“go语言免费学习笔记(深入)”;
type BigStruct struct {
Data [2048]int64
Meta map[string]string
}
func process(bs *BigStruct) { /* ... */ } // 传指针:仅 8 字节
func processCopy(bs BigStruct) { /* ... */ } // 值传:至少 2048×8 = 16KB 拷贝别被“指针=高效”直觉带偏
Go 的函数参数永远是值传递,*T 传递的是指针值本身 —— 它仍是拷贝,只是拷贝的是地址。关键不是“用了指针”,而是“是否避免了大块数据复制”:
- 逃逸分析(
go build -gcflags="-m")比直觉更可靠:如果T值传不逃逸,它就在栈上,很快;若传*T导致原变量逃逸,整体反而更慢 - 接口类型(如
io.Reader)本身已是指针级抽象,再传*os.File没意义,os.File本身就是引用类型(含文件描述符和互斥锁) - benchmark 要测真实路径:用
go test -bench,关注 allocs/op 和 B/op,不能只看时间
最常被忽略的一点:是否需要修改原值,比“省不省内存”优先级更高。先想清楚语义,再决定传值还是传指针。










