go语言函数传参传指针和传值的效率分析

本文探讨了Go语言中的逃逸分析,它决定了内存是在栈上分配还是在堆上分配。逃逸分析影响函数参数传递的方式,传指针可能导致变量逃逸到堆上,增加GC负担。当变量较小,拷贝成本低于逃逸成本时,传值可能更优。逃逸分析会在变量共享、栈空间不足或使用interface时发生。理解逃逸分析对于进行性能优化至关重要。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自:https://zhuanlan.zhihu.com/p/59751716
原作者github:https://github.com/lvgithub/go_blog/blob/master/Escape/Escape.md

函数传递指针还是传值?
两种选择的本质区别是什么?
哪种方式的性能更高呢?

先说结论:不一定

逃逸分析

Go中有一个很重要的概念就是逃逸分析。
逃逸分析是指由编译器决定内存分配的位置。

  • 分配在栈上:函数运行结束后自动回收
  • 分配在堆上:函数运行结束后由GC回收

最终执行效率和这两种分配规则有重要联系。

分析

直观上看,传指针不涉及值拷贝,效率肯定更高,但是实际情况是传指针会导致变量逃逸到堆上,这会增加GC的负担,而且在堆上分配内存会比在栈上分配内存效率更低。

如果传递的变量比较小,拷贝造成的负担小于逃逸的负担(分配堆内存+GC),那么就会降低整体的效率。

栈上的值:分配内存效率高,减少了GC的压力,但是要维护多个副本
堆上的值:分配内存效率低,增加了GC的压力,但是只需要维护一个值

什么情况下会发生逃逸

  • 共享了栈上的值
  • 栈空间不足(比如创建一个超大的slice,超过了栈的空间)
  • 动态类型逃逸,函数参数为interface类型(经典的fmt.Println方法)
  • 闭包引用对象,其本质还是共享了栈上的值
### 关于C++函数参数传递常量指针 #### 使用场景 在某些情况下,希望确保函数不会修改通过指针递的数据。这可以通过使用常量指针实现。例如: ```cpp void printValue(const int* ptr) { if (ptr != nullptr) { std::cout << *ptr; } } ``` 上述代码展示了如何声明接受 `const int*` 类型参数的函数[^3]。 这种做法特别适用于以下几种情形: - 当需要向函数提供只读访问权限时; - 需要保护原始数据免受意外更改影响的情况下; #### 注意事项 当处理涉及常量指针作为参数的情况时需要注意几个方面: 1. **区分不同形式** 存在两种主要形式的常量指针:指向常量对象的非常量指针 (`T const*`) 既是指向常量也是自身的常量指针 (`T const* const`)。前者允许改变指针本身指向的位置但不允许修改其所指向的对象;后者则完全固定了指针及其目标位置不可变性[^5]。 2. **初始化** 如果定义了一个指向常量的指针,则该指针只能绑定到具有相同或更严格限定符的目标上。比如,如果有一个整数变量 `a` 被声明为 `const int a = 10;` ,那么可以创建一个指向它的 `const int* p = &a;` 。但是反过来却不行——尝试将非恒定对象赋给这样的指针会导致编译错误。 3. **返回局部变量地址的风险** 不应让函数返回指向其内部临时分配空间(如栈上的自动变量)的任何种类的指针,因为一旦调用结束这些内存区域就会失效。对于这种情况应当考虑采用其他机制如智能指针或者动态分配资源并由接收方负责释放它们[^4]。 4. **接口设计考量** 设计API时指定参数为常量指针有助于达意图,并且能够帮助开发者更好地理解哪些部分不应该被改动。此外还可以利用编译器强制执行此规则从而减少程序中的逻辑缺陷风险。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值