记录一次golang中关于值传递和引用传递,内存逃逸的学习笔记

server/2024/12/18 8:07:48/

起因:最近在翻看代码时,发现有的同时在使用golang gorm库查询单条数据时,和官方文档中有点区别:

同事的代码大致长这样:

golang">// 依据商品id查询商品详情
func (m GoodsModel) FindOneById(id uint32, field string) (*Goods, error) {info := &Goods{}db := mysqldriver.GetDB()err := db.Table(m.TableName()).Select(field).Where("id = ?", id).First(info).Errorif err != nil && err != gorm.ErrRecordNotFound {return info, err}return info, nil
}

如果这段代码是我来写大致长这样:

golang">// 依据商品id查询商品详情
func (m GoodsModel) FindOneById(id uint32, field string) (Goods, error) {info := Goods{}db := mysqldriver.GetDB()err := db.Table(m.TableName()).Select(field).Where("id = ?", id).First(&info).Errorif err != nil && err != gorm.ErrRecordNotFound {return info, err}return info, nil
}

gorm官方文档中给出的案例:

在这里插入图片描述

在我们的逻辑层是创建一个新的变量来接收FindOneById的返回值
大致长这样:

golang">var res GooodsInfoResponse// 上面巴拉巴拉一堆逻辑// 查询sdb_goods商品信息
goodsInfo, _ := NewGoodsModel.FindOneById(31415, "id,name")		// 下面也是巴拉巴拉一堆逻辑
// 但是在我们的逻辑层,并不会把goodsInfo返回出去
// 而是获取goodsInfo的值赋值到新的返回结构体中res.Name = goodsInfo.Namereturn res, nil

所以我的疑问点就在于, 同事为什么会在FindOneById时将变量的指针地址返回出去
就我目前的了解,这会导致内存逃逸

重点来了
我所理解的相关知识

1.栈和堆的内存管理机制与变量的生命周期密切相关。简单来说,栈上分配的内存相对较小、生命周期较短,而堆上分配的内存较大、生命周期较长。Go 的垃圾回收器(GC)负责管理堆内存,自动回收不再使用的对象

2.逃逸分析决定了一个变量是否需要分配到堆上,主要看变量的生命周期。具体来说,如果变量 逃出了它所在的函数或者作用域(即超出了栈的作用范围),Go 会将其分配到堆上。

golang">// 由于我们返回了 a 的地址,a 会“逃逸”到堆上,因为它需要在 bar 函数外部存活
func bar() *int {a := 10      // 变量a分配在栈上return &a    // 返回a的地址,导致a逃逸到堆上
}

然后我同事的解释有两点,我总结如下

1.指针地址是因为我们的变量有可能很大,在变量很大的情况下有可能会被自动分配到堆,所以返回指针地址

这一点据我了解,逃逸分析的核心是生命周期,而不是变量的大小。如果一个变量在函数外部仍然需要使用(比如返回值或者跨函数传递),那么它会被分配到堆上,不论它的大小如何。

2.在使用gorm中First方法时,本身就是将指针地址传递进去,干脆就直接申明指针地址,而不是直接申明变量,因为将栈上的变量指针地址传递给另一个方法时,会将栈上的变量重新分配到堆上.

这一点要懂哥来给我科普一下gorm包内部有没有什么知识点

至于 栈上的变量指针地址传递给另一个方法时,会将栈上的变量重新分配到堆上 这一点,我敢肯定的是,不会;这很明显是在狡辩,本来分配在栈上的变量怎么可能因为你获取变量的指针地址而发生逃逸呢?
获取 &a(即取地址)并不会立即将变量移到堆上,除非该地址被传递到外部,导致变量逃逸。获取指针本身通常是一个低开销的操作。

栈和堆的性能差异
栈上的内存访问速度较快,适合短生命周期的局部变量。
堆上的内存需要通过指针访问,访问速度较慢,且涉及到垃圾回收等额外开销。


虽然我们的系统跑的好好的,为什么觉得我还是觉得需要修改这段代码,是因为我始终觉得,当一个变量超出了作用域的时候就应该被销毁掉,不能过度依赖语言的垃圾回收机制,GC嘛本来就是一个开销比较大的操作,这里就不得不提Rust的强大了,人家压根就没有垃圾回收机制


http://www.ppmy.cn/server/151121.html

相关文章

二叉树理论基础篇

这里写目录标题 二叉树的种类**满二叉树(Full Binary Tree)****完全二叉树(Complete Binary Tree)****二叉搜索树(Binary Search Tree,BST)**平衡二叉搜索树 二叉树的存储方式二叉树的遍历方式二…

Python中工具脚本在本地共享给不同项目

哈喽,大家好,我是木头左! 在软件开发过程中,经常遇到需要在多个项目中共享工具脚本的情况。例如,数据处理脚本、自动化测试脚本或者通用的实用函数库等。这些工具脚本可以在不同项目中重复使用,从而减少开发时间,提高代码一致性和可维护性。然而,如何有效地管理和共享这…

项目17:简易文字冒险小游戏 --- 《跟着小王学Python·新手》

项目17:简易文字冒险小游戏 — 《跟着小王学Python新手》 《跟着小王学Python》 是一套精心设计的Python学习教程,适合各个层次的学习者。本教程从基础语法入手,逐步深入到高级应用,以实例驱动的方式,帮助学习者逐步掌…

MySQL其五,索引详解,逻辑架构,SQL优化等概念

目录 一、索引 1、索引的概念 2、索引的优缺点 3、添加索引的原则 4、索引的分类 5、索引如何使用 6、存储过程讲解 7、测试索引的效率 7、索引的数据结构 8、覆盖索引(SQL优化的点) 9、最佳左前缀法则(SQL优化的点) 二…

Spring Boot用两种方式访问JSP资源

文章目录 1. Spring Boot展现层2. 创建Spring Boot项目2.1 创建项目2.2 添加依赖支持JSP与JSTL2.3 创建问候控制器3. 采用配置类方式访问JSP页面3.1 创建目录以及页面3.2 创建配置类定义内部资源视图解析器3.3 启动应用,查看结果4. 采用设置应用属性方式4.1 配置视图前后缀属性…

ArcGIS;InVEST实践;生物多样性生境质量模型、固碳模块、城市热岛缓解(降温)模块

以InVEST模型结合实际项目进行由浅入深的实战技术讲解,针对学者的特点及需求进行分析,融合内容体系,对接工作实际项目及论文写作,解决参会者关注的重点及实际项目过程问题,采取逐步延伸的逻辑,不论您是小白…

从Servlet到Spring MVC,从Spring MVC到Spring BootC

从Servlet到Spring MVC 文章目录 从Servlet到Spring MVCServlet服务端的Java应用程序MVC设计模式 Servlet服务端的Java应用程序 Servlet是一种独立于操作系统平台和网络传输协议的服务端的Java应用程序,他用来扩展服务器的功能,可以生成动态的Web页面。…

k8s+rancher配置滚动发布更新时服务不可用

问题 配置完了k8s优雅下线后,发现配置了滚动发布后,两个服务同时在running状态,其中旧服务开始下线会导致有三四秒的时间调用该服务的接口会负载均衡到该服务,接口调用就会报错服务异常。 经排查,具体原因是服务虽然…