首页 星云 工具 资源 星选 资讯 热门工具
:

PDF转图片 完全免费 小红书视频下载 无水印 抖音视频下载 无水印 数字星空

Go plan9 汇编:内存对齐和递归

编程知识
2024年09月02日 09:29

原创文章,欢迎转载,转载请注明出处,谢谢。


Go plan9 汇编系列文章:


0. 前言

在 Go plan9 汇编系列文章中,介绍了函数和函数栈的调用。这里继续看内存对齐和递归调用方面的内容。

1. 内存对齐

直接上示例:

type temp struct {
	a bool
	b int16
	c []string
}

func main() {
	var t = temp{a: true, b: 1, c: []string{}}
	fmt.Println(unsafe.Sizeof(t))
}

输出:

32

改写 temp 结构体成员变量位置:

type temp struct {
	a bool
    c []string
	b int16
}

func main() {
	var t = temp{a: true, b: 1, c: []string{}}
	fmt.Println(unsafe.Sizeof(t))
}

输出:

40

为什么移动下结构体成员的位置会对结构体在内存中的大小有影响呢?

打印示例中结构体成员变量地址如下:

# 示例 1
func main() {
	var t = temp{a: true, b: 1, c: []string{}}

	fmt.Println(unsafe.Sizeof(t.a), unsafe.Sizeof(t.b), unsafe.Sizeof(t.c))
	fmt.Printf("%p %p %p %p\n", &t, &t.a, &t.b, &t.c)

	fmt.Println(unsafe.Sizeof(t))
}

# go run ex10.go 
1 2 24
0xc0000a4000 0xc0000a4000 0xc0000a4002 0xc0000a4008
32

# 示例 2
func main() {
	var t = temp{a: true, b: 1, c: []string{}}

	fmt.Println(unsafe.Sizeof(t.a), unsafe.Sizeof(t.c), unsafe.Sizeof(t.b))
	fmt.Printf("%p %p %p %p\n", &t, &t.a, &t.c, &t.b)

	fmt.Println(unsafe.Sizeof(t))
}

# go run ex10.go 
1 24 2
0xc00006e090 0xc00006e090 0xc00006e098 0xc00006e0b0
40

可以看到,在为结构体分配内存时是要遵循内存对齐的,内存对齐是为了简化寻址,CPU 可一次找到变量的位置。因为内存对齐的存在,这里示例 2 中虽然变量 a 只占 1 个字节,但却独占了 8 个字节,这对于写代码来说是一种内存消耗,应当避免的。

2. 递归

我们看一个递归的示例:

func main() {
	println(sum(1000))
}

//go:nosplit
func sum(n int) int {
	if n > 0 {
		return n + sum(n-1)
	} else {
		return 0
	}
}

输出:

# go run ex7.go 
# command-line-arguments
main.sum: nosplit stack over 792 byte limit
main.sum<1>
    grows 24 bytes, calls main.sum<1>
    infinite cycle

这里我们在 sum 函数前加 //go:nosplit 是要声明这个函数是不可栈分裂的函数。意味着当函数栈满的时候,(内存分配器)不会为它开辟新的空间。

Go 为 goroutine 分配的初始栈空间大小为 2K,如果 main 栈加上 nosplit 的 sum 栈超过 2K,将导致爆栈。

//go:nosplit 拿掉,重新执行:

func main() {
	println(sum(100000))
}

func sum(n int) int {
	if n > 0 {
		return n + sum(n-1)
	} else {
		return 0
	}
}

输出:

5000050000

那么 sum 是否可以无限递归呢?我们给 sum 一个大数 10000000000000,接着重新执行:

runtime: goroutine stack exceeds 1000000000-byte limit
runtime: sp=0xc0200f8398 stack=[0xc0200f8000, 0xc0400f8000]
fatal error: stack overflow

输出 stack overflow,main 协程的栈是从 0xc0200f8000 到 0xc0400f8000,这里递归所用的栈超过了 goroutine 栈的最大限制 1000000000-byte(超过的意思是 main 栈加上 sum 递归调用的栈超过了最大限制),也就是 1G。


From:https://www.cnblogs.com/xingzheanan/p/18392271
本文地址: http://shuzixingkong.net/article/1655
0评论
提交 加载更多评论
其他文章 又一个Rust练手项目-wssh(SSH over Websocket Client)
原文地址https://blog.fanscore.cn/a/61/ 1. wssh 1.1 开发背景 公司内部的发布系统提供一个连接到k8s pod的web终端,可以在网页中连接到k8s pod内。实现原理大概为通过websocket协议代理了k8s pod ssh,然后在前端通过xterm.js
又一个Rust练手项目-wssh(SSH over Websocket Client) 又一个Rust练手项目-wssh(SSH over Websocket Client) 又一个Rust练手项目-wssh(SSH over Websocket Client)
WiFi基础(二):最新WiFi信道、无线OSI模型与802.11b/g/n
liwen01 2024.09.01 前言 最近十几年,通信技术发展迅猛,通信标准更新频繁,有的设备还在使用 802.11/b/g/n 协议,有的已支持到 WiFi6、WiFi7。 而国内有关无线 WiFi 的书籍或资料却很少,就算能找着的,大多也是比较老旧。本文试图使用最新的数据来介绍 WiFi
WiFi基础(二):最新WiFi信道、无线OSI模型与802.11b/g/n WiFi基础(二):最新WiFi信道、无线OSI模型与802.11b/g/n WiFi基础(二):最新WiFi信道、无线OSI模型与802.11b/g/n
【ETL工具】DataX + DataXWeb 初使用过程记录
ETL:将大量的原始数据,经过抽取(Extract)和清洗转换(Transform)后,加载(Load)到目的端的过程,称为ETL,实现这种过程的工具,也就是ETL工具 版本:DataX v202309 DataXWeb 2.1.3-alpha-release DataX:阿里云开源的一个异构数据源
【ETL工具】DataX + DataXWeb  初使用过程记录 【ETL工具】DataX + DataXWeb  初使用过程记录 【ETL工具】DataX + DataXWeb  初使用过程记录
PHP转Go系列 | ThinkPHP与Gin框架之Redis延时消息队列技术实践
我们在某宝或某多多上抢购商品时,如果只是下了订单但没有进行实际的支付,那在订单页面会有一个支付倒计时,要是过了这个时间点那么订单便会自动取消。在这样的业务场景中,一般情况下就会使用到延时队列。
PHP转Go系列 | ThinkPHP与Gin框架之Redis延时消息队列技术实践 PHP转Go系列 | ThinkPHP与Gin框架之Redis延时消息队列技术实践 PHP转Go系列 | ThinkPHP与Gin框架之Redis延时消息队列技术实践
PyTorch从入门到放弃之张量模块
目录张量的数据类型torch.rand()函数torch.randn()函数torch.normal()函数torch.linspace()函数torch.manual_seed()函数torch.ones()、torch.zeros()、torch.eye()张量的基本操作增加和删除维度交换维度拼
PyTorch从入门到放弃之张量模块 PyTorch从入门到放弃之张量模块 PyTorch从入门到放弃之张量模块
六,Spring Boot 容器中 Lombok 插件的详细使用,简化配置,提高开发效率
六,Spring Boot 容器中 Lombok 插件的详细使用,简化配置,提高开发效率 @目录六,Spring Boot 容器中 Lombok 插件的详细使用,简化配置,提高开发效率1. Lombok 介绍2. Lombok 常用注解2.1 @ToString2.2 @Setter2.3 @Dat
六,Spring Boot 容器中 Lombok 插件的详细使用,简化配置,提高开发效率 六,Spring Boot 容器中 Lombok 插件的详细使用,简化配置,提高开发效率 六,Spring Boot 容器中 Lombok 插件的详细使用,简化配置,提高开发效率
manim边学边做--带箭头直线
带箭头的直线就是有方向的直线,既可以用来表示矢量,也可以用来标记某个关键位置。manim中提供了4种常用的带箭头的直线模块: Arrow:单箭头的直线 DoubleArrow:双箭头的直线 LabeledArrow:带标签的直线 Vector:向量 其中,DoubleArrow,LabeledArr
manim边学边做--带箭头直线 manim边学边做--带箭头直线 manim边学边做--带箭头直线
《花100块做个摸鱼小网站! 》第五篇—通过xxl-job定时获取热搜数据
⭐️基础链接导航⭐️ 服务器 → ☁️ 阿里云活动地址 看样例 → &#128031; 摸鱼小网站地址 学代码 → &#128187; 源码库地址 一、前言 我们已经成功实现了一个完整的热搜组件,从后端到前端,构建了这个小网站的核心功能。接下来,我们将不断完善其功能,使其更加美观和实用。今天的主题是
《花100块做个摸鱼小网站! 》第五篇—通过xxl-job定时获取热搜数据 《花100块做个摸鱼小网站! 》第五篇—通过xxl-job定时获取热搜数据 《花100块做个摸鱼小网站! 》第五篇—通过xxl-job定时获取热搜数据