web-dev-qa-db-ja.com

Goでのスライスの最大長

4Gbマシンの64ビットLinux OSで次のコードを実行しています。

package main

import (
    "fmt"
    "math"
)

func main() {
    r := make([]bool, math.MaxInt32)

    fmt.Println("Size: ", len(r))
}

これを実行すると、次のようになります。

Size: 2147483647

math.MaxInt32math.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のスライスインデックスは1つの特定のタイプにバインドされていますか?

編集:

boolの代わりにstruct{}を使用してテストを実行し、math.MaxInt64要素を割り当てました。すべてが期待通りに進み、印刷されます:

Size: 9223372036854775807

では、別の質問ですが、エラーが同じ(メモリ不足)のように思われるのに、なぜ2つの異なるエラーメッセージが表示されるのでしょうか。

各エラーがポップアウトする条件は何ですか?

15
Simón Oroño

ドキュメントによると、The elements can be addressed by integer indices 0 through len(s)-1。これは、スライスの最大容量がターゲットビルドのデフォルトの整数のサイズであることを意味します。

編集:ソースコードを見ると、このサイズのスライスが可能な限り確実であることを確認する安全チェックがあるようです:

_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"))
    }
_

したがって、この場合はuintptr(len) > maxmem/uintptr(t.elem.size)のように見えるため、このサイズの割り当てを行うことはできません。

ただし、メモリを消費しない_struct{}_を割り当てると、このサイズが許可されます。

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