Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >golang | 是返回struct还是返回struct的指针

golang | 是返回struct还是返回struct的指针

作者头像
KINGYT
发布于 2021-08-13 06:26:11
发布于 2021-08-13 06:26:11
4.1K0
举报

当我们定义一个函数时,是返回结构体呢,还是返回指向结构体的指针呢?

对于这个问题,我想大部分人的回答,肯定都是返回指针,因为这样可以避免结构体的拷贝,使代码的效率更高,性能更好。

但真的是这样吗?

在回答这个问题之前,我们先写几个示例,来确定一些基本事实:

上图中,函数f返回的是结构体S的指针,即一个地址,这个可以通过其汇编来确认:

看上图中的选中行。

第一行是调用函数f,其结果,即结构体S的指针,或结构体S的地址,是放到ax寄存器中返回的。

第二行用0x8(ax),即ax中的地址加8的形式,来获得结构体S中a2字段的值,然后将该值和0x2相比,以进行后续逻辑。

由此可见,返回结构体指针的形式,确实是只传递了一个地址。

我们再来看下返回结构体的情况:

这次函数f返回的是S,而不是*S,看看这样写其汇编是什么样子:

上图main函数的汇编中,通过调用函数f,初始化了main函数栈中,0x0(sp)到0x50(sp)的内存段,该内存段共有80个字节,正好对应于结构体S的大小。

在函数f返回后,sp寄存器存放的,正是函数f初始化的结构体S的地址。

接着,我们看上图中的选中行,该段逻辑通过runtime.duffcopy函数,将栈中内存段0x0(sp)到0x50(sp)的值,拷贝到了内存段0x50(sp)到0xa0(sp)的部分,即将函数f初始化的结构体S,从内存地址0x0(sp),拷贝到了0x50(sp)。

然后,通过0x58(sp),即sp中的地址加上0x58的形式,获得拷贝后的结构体S中,a2字段的值,最后将其和0x2比较,以进行后续逻辑。

由上可见,当函数返回结构体时,确实存在着一次结构体的拷贝操作。

对比以上两个示例我们看到,返回指针的确会更好些,因为这样节省了一次结构体的拷贝操作。

但这样性能就真的更好吗?

写个benchmark测试下:

执行看下结果:

这两个benchmark的时间几乎是相等的,其结果并不像我们预料的那样,返回指针的形式会更快些。

为什么呢?

看下这两个benchmark对应的汇编:

它们居然都被优化成了空跑for循环了,难怪这两个测试耗时是一样的。

加上编译器指令//go:noinline,防止f1/f2函数被内联,进而被过度优化:

如上图的第9行和第14行。

再来看下测试程序的汇编,确保以上操作是有效的。

先看下函数f1及其对应的benchmark:

再看下函数f2及其对应的benchmark:

这次这两个都没有问题。

再来跑下benchmark:

这次结果显示,f2函数,即返回结构体形式,比f1函数,即返回指针的形式,居然快了将近5倍,意不意外?

这是为什么呢?

其实在上图中,就有一些线索。

看BenchmarkF1那行,其最后两列显示,每次调用f1函数,都会有一次堆内存分配操作,其分配内存的大小为80字节,正好对应于结构体S的大小,也就是说,f1函数中结构体S的内存,都是在堆上分配的。

而在BenchmarkF2中,就没有发生堆内存的分配操作,f2函数中的结构体S,都是在栈上分配的。

这个也可以通过上面展示的,f1/f2函数的汇编代码看到。

f1函数的汇编是通过runtime.newobject在堆上分配内存的,而f2函数则是直接就在栈上把内存分配好了,并没有调用runtime.newobject函数。

那为什么在堆上分配内存,会比在栈上分配内存慢这么多呢?

有两点原因,一是在堆上分配内存的函数runtime.newobject,其本身逻辑就比较复杂,二是堆上分配的内存,后期还要通过gc来对其进行内存回收,这些逻辑加起来,远比在栈上分配内存,外加一次拷贝操作要耗时的多。

有关go内存是在堆上分配的,还是在栈上分配的,这个是在编译过程中,通过逃逸分析来确定的,其主体思想是:

假设有变量v,及指向v的指针p,如果p的生命周期大于v的生命周期,则v的内存要在堆上分配。

其实逃逸分析的具体逻辑,远比上面说的复杂,如果有兴趣研究代码,可以从下面开始入手:

当然,我们也可以在编译时,通过加上-m参数,来让编译器告诉我们,一个变量到底是分配在堆上,还是在栈上:

看上图,f1函数中的&S{...}逃逸到了堆上,即是在堆上分配的。

以上是对80字节大小的结构体,返回指针和返回值情况的比较,那如果结构体字节数更小或更大会怎么样呢?

经过测试,1MiB字节以下,返回结构体都更有优势。

那返回指针的方式是不是没用了呢?也不是,如果你最终的结构体,就是要存放到堆里,比如要存放到全局的map里,那返回指针优势就更大些,因为其省去了返回结构体时的拷贝操作。

就这些,希望对你有所帮助。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-08-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Linux内核及JVM底层相关技术研究 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
JAVA使用JAVACV实现图片合成短视频,并给视频添加音频!!!
玩抖音的时候,发现可以根据图片生成视频,并添加音频,同时刚好在项目当中也遇到需要利用多张图片生成视频的操作,特此记录下实现的过程!!!
海加尔金鹰
2020/06/09
9.2K0
续更—Java游戏编程不完全详解-4
当我们玩游戏时,我们可能会听到声效,但是不会真正注意它们。因为希望听到他们,所以声效在游戏中是非常重要的。
老九君
2021/10/13
1K0
续更—Java游戏编程不完全详解-4
猫头虎分享:如何在Java中使用FFmpeg解析视频时长、封面和大小
在Java开发中,处理视频文件的时长、封面和大小等信息是常见需求。为此,Java提供了多种库来实现这些功能。本文将对比几种常用的Java视频处理库,并提供使用JavaCV获取视频信息的示例代码。
猫头虎
2024/11/18
8310
猫头虎分享:如何在Java中使用FFmpeg解析视频时长、封面和大小
JavaCV的摄像头实战之七:推流(带声音)
本篇概览 本文是《JavaCV的摄像头实战》的第七篇,在《JavaCV的摄像头实战之五:推流》一文中,咱们将摄像头的内容推送到媒体服务器,再用VLC成功播放,相信聪明的您一定觉察到了一缕瑕疵:没有声音 虽然《JavaCV的摄像头实战》系列的主题是摄像头处理,但显然音视频健全才是最常见的情况,因此就在本篇补全前文的不足吧:编码实现摄像头和麦克风的推流,并验证可以成功远程播放音视频 关于音频的采集和录制 本篇的代码是在《JavaCV的摄像头实战之五:推流》源码的基础上增加音频处理部分 编码前,咱们先来分析一下,
程序员欣宸
2021/12/07
1.8K0
JavaCV的摄像头实战之七:推流(带声音)
【详解】Java实现视频格式转化
在当今数字化时代,视频已成为我们日常生活和工作中不可或缺的一部分。不同的设备和平台可能支持不同的视频格式,因此,视频格式转换的需求也日益增长。Java作为一种广泛使用的编程语言,其强大的跨平台特性和丰富的库支持使得它成为实现视频格式转换的理想选择。本文将介绍如何使用Java实现视频格式转换。
大盘鸡拌面
2024/12/31
4010
为自己的短视频盖一个专属的印章----JavaCV之流媒体水印
无论是歌曲,小说,还是技术文章从古至今都是各种抄袭,各种拿来就用,随着技术的发展,朋友圈的图片,商铺的图片,也开始各种拿来就用,所以发明了水印,当然不止图片有水印,视频也可以有的。
用户2242639
2021/06/29
2.3K0
JavaCV的摄像头实战之六:保存为mp4文件(有声音)
本篇概览 本文是《JavaCV的摄像头实战》的第六篇,在《JavaCV的摄像头实战之三:保存为mp4文件》一文中,咱们将摄像头的内容录制为mp4文件,相信聪明的您一定觉察到了一缕瑕疵:没有声音 虽然《JavaCV的摄像头实战》系列的主题是摄像头处理,但显然音视频健全才是最常见的情况,因此就在本篇补全前文的不足吧:编码实现摄像头和麦克风的录制 关于音频的采集和录制 本篇的代码是在《JavaCV的摄像头实战之三:保存为mp4文件》源码的基础上增加音频处理部分 编码前,咱们先来分析一下,增加音频处理后具体的代码逻
程序员欣宸
2021/12/07
8710
JavaCV的摄像头实战之六:保存为mp4文件(有声音)
语音识别 | Java 实现 AI 人工智能技术 - 语音识别功能
说到语音识别、语音翻译、图像识别、人脸识别等等,现在已经非常非常非常普及了,看过‘最强大脑’的朋友,也应该对‘小度’这个机器人有所了解,战胜国际顶尖的‘大脑’- 水哥,(PS:内幕不知),那么今天,我们来看下关于语音识别,是如何做到的,Java又是如何识别语音的?如何转换语音?
码神联盟
2018/07/30
8K0
语音识别 |  Java 实现 AI 人工智能技术 - 语音识别功能
rtsp 获取视频流 java_Java获取rtsp视频流,实现rtsp流预览功能,并将视频流每帧保存成图片…
public static void testzc() throws FrameGrabber.Exception
全栈程序员站长
2022/11/07
3.4K0
java实现MP3
http://www.javazoom.net/mp3spi/mp3spi.html
py3study
2020/01/08
2.1K0
JavaCV推流实战(MP4文件)
本篇概览 自己的mp4文件,如何让更多的人远程播放?如下图所示: 这里简单解释一下上图的功能: 部署开源流媒体服务器SRS 开发名为PushMp4的java应用,该应用会读取本机磁盘上的Mp4文件,读取每一帧,推送到SRS上 每个想看视频的人,就在自己电脑上用流媒体播放软件(例如VLC)连接SRS,播放PushMp4推上来的视频 今天咱们就来完成上图中的实战,整个过程分为以下步骤: 环境信息 准备MP4文件 用docker部署SRS java应用开发和运行 VLC播放 环境信息 本次实战,我这边涉及
程序员欣宸
2021/12/07
1.5K2
JavaCV推流实战(MP4文件)
通过ChatGPT使用JavaCV
最近我在自己的服务器里基于Pandora搭建了ChatGPT页面,以后只需要accessToken或者key就可以使用,不再需要再去官网玩了,省下了不少时间。
编程思维
2024/06/24
1450
通过ChatGPT使用JavaCV
使用摄像头+JavaCV做人脸识别
上一文,我们讲到的是使用JavaCV拉取笔记本摄像头画面,这次,我们基于上一次的基础,加工人脸识别功能。
灬沙师弟
2023/09/06
1K0
使用摄像头+JavaCV做人脸识别
自己开发一个电视----流媒体之JavaCV
流媒体到底是什么?百度百科上是这么讲:“流媒体(streaming media)是指将一连串的媒体数据压缩后,经过网上分段发送数据,在网上即时传输影音以供观赏的一种技术与过程,此技术使得数据包得以像流水一样发送;如果不使用此技术,就必须在使用前下载整个媒体文件。流式传输可传送现场影音或预存于服务器上的影片,当观看者在收看这些影音文件时,影音数据在送达观看者的计算机后立即由特定播放软件播放。”
用户2242639
2021/06/29
2.5K1
云端录制直播流视频,上传云盘
哪一天我心血来潮,想把我儿子学校的摄像头视频流录制下来,并保存到云盘上,这样我就可以在有空的时候看看我儿子在学校干嘛。想到么就干,当时花了一些时间开发了一个后端服务,通过数据库配置录制参数,以后的设想是能够通过页面去配置,能够自动捕获直播视频流,这还得要求自己先学会vue,所以还得缓缓。
阿提说说
2024/02/04
3430
云端录制直播流视频,上传云盘
Java 视频处理:基于 MD5 校验秒传及 ffmpeg 切片合并的实现
本文介绍两种网络技术实现方法。一是 MD5 校验秒传,服务器端用数据库记上传文件 MD5 值及存储路径,Java 代码接收客户端 MD5 值并查询校验,返回状态码。二是用 ffmpeg 切片视频成 m3u8 上传,异步合并文件实现视频按需加载。
Yeats_Liao
2025/01/09
1710
Java 视频处理:基于 MD5 校验秒传及 ffmpeg 切片合并的实现
JavaCV的摄像头实战之一:基础
关于《JavaCV的摄像头实战》系列 《JavaCV的摄像头实战》顾名思义,是使用JavaCV框架对摄像头进行各种处理的实战集合,这是欣宸作为一名Java程序员,在计算机视觉(computer vision)领域的一个原创系列,通过连续的编码实战,与您一同学习掌握视频、音频、图片等资源的各种操作 另外要说明的是,整个系列使用的摄像头是USB摄像图或者笔记本的内置摄像头,并非基于网络访问的智能摄像头 本篇概览 作为整个系列的开篇,本文非常重要,从环境到代码的方方面面,都会为后续文章打好基础,简单来说本篇由以下
程序员欣宸
2021/12/07
1.9K2
JavaCV的摄像头实战之一:基础
C++与音视频处理:处理音频和视频数据的编码和解码
音视频处理在现代多媒体应用中起着重要的作用。C++是一种强大且广泛使用的编程语言,提供了许多用于处理音频和视频数据的库和工具。本文将介绍C++中常用的音频和视频编码解码技术,以及相关的库和工具。
大盘鸡拌面
2023/12/04
1.1K0
ChatGPT教你如何拉取本机摄像头
最近了不起在自己的服务器里基于Pandora搭建了ChatGPT页面,以后只需要accessToken或者key就可以使用,不再需要再去官网玩了,省下了不少时间。
灬沙师弟
2023/09/06
7990
ChatGPT教你如何拉取本机摄像头
JavaCV人脸识别三部曲之三:识别和预览
-若真如上图所示,那么显然confidence越小,是郭富城的可能性就越大了,接下来再去找一些权威的说法:
程序员欣宸
2022/01/06
1.1K1
JavaCV人脸识别三部曲之三:识别和预览
推荐阅读
相关推荐
JAVA使用JAVACV实现图片合成短视频,并给视频添加音频!!!
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档