在Go语言中,切片的最大长度是多少?

huangapple go评论86阅读模式
英文:

Maximum length of a slice in Go

问题

我在一台4GB内存的64位Linux操作系统上运行以下代码:

package main

import (
    "fmt"
    "math"
)

func main() {
    r := make([]bool, math.MaxInt32)
    
    fmt.Println("Size: ", len(r))
}

当我运行这段代码时,输出结果为:

Size: 2147483647

如果我将math.MaxInt32更改为math.MaxUint32,则会出现以下错误:

fatal error: runtime: out of memory

使用math.MaxUint32作为切片大小时,我遇到了内存不足的问题,这是我预料到的。但是,当我尝试使用math.MaxInt64时,出现以下错误:

panic: runtime error: makeslice: len out of range

所以显然我不能创建一个大小为math.MaxInt64的切片,这就引出了我的问题:如果内存不是问题,我在Go中能创建的最大切片是多大?

我记得在Java中,原始数组的索引是使用int类型管理的,因此原始数组的最大大小是int的最大值。如果你尝试使用long类型,它会引发异常(据我所记)。在Go中是否也是如此?Go中的切片索引是否限定为一种特定类型?

编辑:

我使用struct{}代替bool,并分配了math.MaxInt64个元素来运行测试。一切都按预期进行,并打印出:

Size: 9223372036854775807

所以,另一个问题是,为什么在看起来错误相同(内存不足)的情况下会出现两个不同的错误消息?

每个错误出现的条件是什么?

英文:

I have the following code running in a 64-bit linux OS in a 4Gb machine:

package main

import (
    "fmt"
    "math"
)

func main() {
    r := make([]bool, math.MaxInt32)
    
    fmt.Println("Size: ", len(r))
}

When I run this I get:

Size: 2147483647

If I change the math.MaxInt32 for math.MaxUint32 I get:

fatal error: runtime: out of memory

With slice size of math.MaxUint32 I ran out of memory, I was expecting that, but when I try using math.MaxInt64 I get:

panic: runtime error: makeslice: len out of range

So aparently I cannot create a slice with a size of math.MaxInt64, which bring us to my question: If the memory is not an issue, what's the biggest slice I cant create in Go?

I remember that, in Java, raw array indexes are managed with the type int, so the maximum size of a raw array is the max value of an int, if you try to do it with long it will raise an exception (as far as I remember), is it the same with Go? are slice index in Go bound to one specific type?

EDIT:

I ran the test using struct{} instead of bool and allocating math.MaxInt64 elements. Everything went as expected, and prints:

Size: 9223372036854775807

So, another question, why there are two different error messages when it seems that the error is the same (not enough memory)?

What are the conditions for each error to pop out?

答案1

得分: 22

根据文档,"元素可以通过整数索引0到len(s)-1进行访问"。这意味着切片的最大容量取决于目标构建中默认整数的大小。

编辑:从查看源代码来看,似乎有一个安全检查来确保切片的大小是可能的:

func makeslice(t *slicetype, len64 int64, cap64 int64) sliceStruct {
    // 注意:这里的 len > MaxMem/elemsize 检查并不是严格必要的,
    // 但它会产生一个“len超出范围”的错误,而不是一个“cap超出范围”的错误,
    // 当有人执行 make([]T, bignumber) 时。'cap超出范围'也是正确的,
    // 但由于 cap 只是隐式提供的,说 len 更清晰。参见 issue 4085。
    len := int(len64)
    if len64 < 0 || int64(len) != len64 || t.elem.size > 0 && uintptr(len) > maxmem/uintptr(t.elem.size) {
        panic(errorString("makeslice: len out of range"))
    }
}

所以在这种情况下,看起来 uintptr(len) > maxmem/uintptr(t.elem.size),所以我们不允许进行这样大小的分配。

然而,当我分配不占用内存的 struct{} 时,这个大小是允许的:

func main(){
    r := make([]struct{}, math.MaxInt64)
    fmt.Println(len(r))
}
// 输出 9223372036854775807
英文:

According to the docs, The elements can be addressed by integer indices 0 through len(s)-1. This means the maximum capacity for a slice is the size of the default integer on the target build.

EDIT: From looking at the source code, it appears that there is a safety check to make sure this size of slice is at all possible:

func makeslice(t *slicetype, len64 int64, cap64 int64) sliceStruct {
	// NOTE: The len &gt; MaxMem/elemsize check here is not strictly necessary,
	// but it produces a &#39;len out of range&#39; error instead of a &#39;cap out of range&#39; error
	// when someone does make([]T, bignumber). &#39;cap out of range&#39; is true too,
	// but since the cap is only being supplied implicitly, saying len is clearer.
	// See issue 4085.
	len := int(len64)
	if len64 &lt; 0 || int64(len) != len64 || t.elem.size &gt; 0 &amp;&amp; uintptr(len) &gt; maxmem/uintptr(t.elem.size) {
		panic(errorString(&quot;makeslice: len out of range&quot;))
	}

So in this case, it looks like uintptr(len) &gt; maxmem/uintptr(t.elem.size) so we're not allowed to do this size of an allocation.

However when I allocate struct{} which takes no memory, this size is allowed:

func main(){
	r := make([]struct{}, math.MaxInt64)
    fmt.Println(len(r))
}
// prints 9223372036854775807

huangapple
  • 本文由 发表于 2014年12月25日 21:43:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/27647737.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定