Go中切片的最大长度

时间:2021-08-16 22:17:57

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

我在4Gb机器上的64位Linux操作系统中运行以下代码:

package mainimport (    "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:

如果我为math.MaxUint32更改了math.MaxInt32,我得到:

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:

使用math.MaxUint32的切片大小,我的内存耗尽,我当时正在等待,但是当我尝试使用math.MaxInt64时,我得到:

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?

所以显然我无法创建一个大小为math.MaxInt64的切片,这让我们想到了一个问题:如果内存不是问题,那么我在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?

我记得在Java中,原始数组索引是用int类型管理的,所以原始数组的最大大小是int的最大值,如果你尝试用long做它会引发异常(至于我记得),和Go一样吗? Go中的切片索引绑定到一个特定类型?

EDIT:

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

我使用struct {}而不是bool运行测试并分配math.MaxInt64元素。一切都按预期进行,并打印:

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 个解决方案

#1


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.

根据文档,元素可以通过整数索引0到len(s)-1来寻址。这意味着切片的最大容量是目标构建上的默认整数的大小。

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 > MaxMem/elemsize check here is not strictly necessary,    // but it produces a 'len out of range' error instead of a 'cap out of range' error    // when someone does make([]T, bignumber). 'cap out of range' is true too,    // but since the cap is only being supplied implicitly, saying len is clearer.    // See 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"))    }

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

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

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

但是当我分配不带内存的struct {}时,允许这个大小:

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

#1


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.

根据文档,元素可以通过整数索引0到len(s)-1来寻址。这意味着切片的最大容量是目标构建上的默认整数的大小。

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 > MaxMem/elemsize check here is not strictly necessary,    // but it produces a 'len out of range' error instead of a 'cap out of range' error    // when someone does make([]T, bignumber). 'cap out of range' is true too,    // but since the cap is only being supplied implicitly, saying len is clearer.    // See 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"))    }

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

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

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

但是当我分配不带内存的struct {}时,允许这个大小:

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