为什么 Go 对于长度为 100k 的切片使用的内存比长度为 100k 的数组要少?
Go语言在处理切片和数组时,对于长度为100k的切片所使用的内存要比长度为100k的数组要少。这是因为切片在底层实现中采用了指针和长度的组合,而数组则需要连续的内存空间来存储数据。由于切片的长度是可变的,所以可以动态地分配和释放内存,而数组则需要在声明时就指定固定的长度。因此,当处理大量数据时,使用切片可以更加高效地利用内存空间,减少内存的占用。这也是Go语言在处理大规模数据时的一个优势之一。
问题内容
考虑以下代码,我分配了 4000 个数组,每个数组长度为 100k:
parentmap := make(map[int][100_000]int) for i := 0; i < 4000; i++ { parentmap[i] = [100_000]int{} time.sleep(3 * time.millisecond) }
如果我在本地运行该程序并分析其内存使用情况,它会开始使用 >2gb 内存。
现在,如果我们稍微更改代码以使用数组切片(但长度也为 100k),如下所示:
parentMap := make(map[int][]int) for i := 0; i < 4000; i++ { parentMap[i] = make([]int, 100_000) time.Sleep(3 * time.Millisecond) }
在我的机器上,内存峰值约为 73mb。 这是为什么?
我认为这两个片段将使用大致相同的内存,原因如下:
- 在这两种情况下,go 运行时都会在堆上分配
parentmap
的值。 go 这样做是因为如果它在堆栈上分配这些值,那么一旦当前函数超出范围,parentmap
的值就会全部清除。 - 因此第一个代码段直接在堆上分配 4k 数组。
- 并且,第二个片段在堆上分配 4k 切片标头。每个切片头都有一个指向大小为 100k 的唯一数组(也在堆上)的指针。
- 在这两种情况下,大小为 100k 的堆上都有 4k 数组。因此,在任何一种情况下都应使用大致相等的内存量。
我读到:https://go.dev/blog/slices-intro。但找不到解释这一点的实现细节。
解决方法
带有切片的版本可能受益于延迟分配。没有任何东西会尝试写入这些片之一的数据缓冲区,因此操作系统可以自由地不为这些缓冲区实际分配内存,直到确实尝试写入。 (操作系统也可以延迟对缓冲区进行零初始化,因此不会强制分配。)
同时,带有数组的版本需要将数组实际复制到映射中,这意味着实际执行写入。即使写入的值全为零,它们仍然是写入,因此操作系统必须实际为要写入的数据分配内存。
尝试将数据写入这些切片,切片版本也应该占用千兆字节的内存。 (我认为每页内存一个值应该足够了,但是用 1
s 填充切片可能会更容易。)
以上是为什么 Go 对于长度为 100k 的切片使用的内存比长度为 100k 的数组要少?的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

Go爬虫Colly中的Queue线程问题探讨在使用Go语言的Colly爬虫库时,开发者常常会遇到关于线程和请求队列的问题。�...

Go指针语法及viper库使用中的寻址问题在使用Go语言进行编程时,理解指针的语法和使用方法至关重要,尤其是在...

Go语言中哪些库是大公司开发或知名开源项目?在使用Go语言进行编程时,开发者常常会遇到一些常见的需求,�...

Go语言中实现高效键值对存储的正确方法在使用Go语言开发类似于Redis的键值对内存存储器时,如何实现最佳性能...

Go框架的受众现状分析在当前的Go编程生态中,开发者们常常面临选择合适的框架来满足其业务需求。今天我们�...

Go语言海量URL访问性能优化策略本文针对使用Go语言处理海量URL访问的问题,提出性能优化方案。现有程序从CSV�...

Go语言中字符串打印的区别:使用Println与string()函数的效果差异在Go...
