值传递的意义和几个例子

举报
码乐 发表于 2025/09/25 08:13:37 2025/09/25
【摘要】 1 简介内存管理机制Go 语言的内存管理是 自动垃圾回收(GC)+ 编译期逃逸分析(Escape Analysis)+ 栈内存分配优化 的组合设计。栈内存分配在函数内部创建的局部变量,Go 会优先分配在栈上。栈的生命周期随着函数调用结束而回收,效率很高。编译器会通过 逃逸分析 判断变量是否可能被函数外部引用:若不会逃逸,则分配在栈上。若可能逃逸(如被返回或闭包引用),则分配在堆上,由 GC...

1 简介内存管理机制

Go 语言的内存管理是 自动垃圾回收(GC)+ 编译期逃逸分析(Escape Analysis)+ 栈内存分配优化 的组合设计。

  • 栈内存分配

在函数内部创建的局部变量,Go 会优先分配在栈上。栈的生命周期随着函数调用结束而回收,效率很高。
编译器会通过 逃逸分析 判断变量是否可能被函数外部引用:

若不会逃逸,则分配在栈上。

若可能逃逸(如被返回或闭包引用),则分配在堆上,由 GC 管理。

  • 垃圾回收(GC)

Go 使用的是 并发标记-清除(Concurrent Mark and Sweep)+ 三色标记算法 的改进版:

GC 在应用运行时并发执行,尽量减少 STW(Stop The World)的时间。

Go 1.8 之后的 GC 目标是将 STW 降到 亚毫秒级,适合大规模并发程序。

  • 内存复用与优化

Go runtime 会维护对象池、内存页(span)等结构,减少频繁的堆分配开销。

2 为什么 Go 的函数一定是值传递?

Go 的函数参数传递机制是 严格的值传递(call by value),原因在于语言设计的简洁性与一致性:

在调用函数时,实参会被复制一份给形参。

如果参数是基础类型(int、string 等),就是值本身的拷贝。

如果参数是引用类型(切片、map、channel、指针),则拷贝的是“引用(指针)”,因此函数内部修改底层数据会影响外部。

这样保证了 所有函数调用的语义一致:永远是值拷贝。
Python 则是 对象引用传递(call by object reference),容易让初学者混淆“值传递”和“引用传递”的概念。

例子:

  func changeSlice(s []int) {
      s[0] = 99      // 修改了底层数组,外部可见
      s = append(s, 100) // 修改了形参 s,不影响外部
  }

这里 s 作为参数时被 值拷贝,但它包含一个指针指向底层数组,所以能修改数组内容。但 append 后的 s 是新拷贝,外部不受影响。

3 代码示例

 	a := 43

  fmt.Println(a)  // 43
  fmt.Println(&a) // 0x20818a220

  var b = &a
  fmt.Println(b)  // 0x20818a220
  fmt.Println(*b) // 43

  *b = 42        // b says, "The value at this address, change it to 42"
  fmt.Println(a) // 42

上面的代码使 b 成为指向存储 int 的内存地址的指针,b 的类型为 “int pointer”
其中 *int – * 是类型的一部分 – b 是 *int 类型

这很有用
我们可以传递一个内存地址而不是一堆值(我们可以传递一个引用)
然后我们仍然可以更改存储在该内存地址中的任何内容的值
这使我们的程序性能更高
我们不必传递大量数据
我们只需要传递地址

当我们传递一个内存地址时,我们传递了一个值

与 C 系列中的所有语言一样,Go 中的所有内容都是通过值传递的。
也就是说,函数总是获取所传递事物的副本,
就好像有一个赋值语句将值分配给参数一样。
例如,将 int 值传递给函数会复制 int,
传递指针值会复制指针,但不会复制它指向的数据。

如果你将变量传递给函数,该函数总是会得到它的副本。永远记住。
如果被调用方修改了 parameter variable,则效果对调用方不可见。

越能认识到 Go 总是通过值传递,再加上支持指针的额外表现力,你就能创建出更清晰的程序

4 内存管理与 Python3 的区别

特性			Go									Python3
内存分配	编译器逃逸分析,局部变量优先分配在栈上;堆内存由 GC 管理	所有对象(即使是整数、字符串)都在堆上分配
垃圾回收	并发三色标记清除 GC(低延迟)	引用计数为主,循环引用通过分代 GC 处理
对象模型	静态类型,编译期决定内存布局	动态类型,所有对象都是 PyObject,内存占用较大
性能影响	内存管理趋近于 C/C++ 效率,适合高并发	引用计数 + 动态类型使得内存管理灵活但开销较高

5 小结:

Go 的设计目标是 高并发、高性能、低延迟,所以强调栈分配和低开销 GC。

Python 的设计目标是 易用性和灵活性,所以所有对象堆分配,引用计数简单直观,但性能相对较低。

Go 的内存管理依赖逃逸分析、栈优先分配和低延迟 GC,追求性能与并发;Python 则依赖堆分配、引用计数和分代 GC,追求灵活性。

Go 的函数参数始终是值传递,保持语义简单一致;而是否能“修改外部”取决于是否传入了引用类型。

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。