ホームページ  >  記事  >  バックエンド開発  >  `println` と `fmt.Println` を混在させると Go のスタックの増加に影響を与えるのはなぜですか?

`println` と `fmt.Println` を混在させると Go のスタックの増加に影響を与えるのはなぜですか?

DDD
DDDオリジナル
2024-11-17 13:58:01392ブラウズ

Why Does Mixing `println` and `fmt.Println` Impact Stack Growth in Go?

Println と Fmt.Println の混合: スタックの増加について理解する

Go では、スタックは変数と関数の引数の格納に対応するために動的に増加します。 。ただし、別の印刷関数を使用すると、この動作が影響を受ける可能性があります。

次の例を考えてみましょう:

package main

import "fmt"

const size = 1024

func main() {
    fmt.Println("Start")
    s := "HELLO"
    stackCopy(&s, 0, [size]int{})
}

func stackCopy(s *string, c int, a [size]int) {
    println("println: ", s, *s)
    //fmt.Println("fmt:     ", s, *s)
    c++
    if c == 10 {
        return
    }
    stackCopy(s, c, a)
}

println のみが使用される場合、スタックの増大に伴って文字列 s のアドレスが変化します。 :

Start
println:  0xc000107f58 HELLO
println:  0xc000117f58 HELLO
println:  0xc000117f58 HELLO

ただし、fmt.Println が println と混合されている場合、または排他的に使用されている場合、s のアドレスは変わりません:

Start
println:  0xc00010a040 HELLO
fmt:      0xc00010a040 HELLO
println:  0xc00010a040 HELLO
fmt:      0xc00010a040 HELLO

違いを理解する

この違いは、println と fmt.Println が引数を処理する方法から生じます。

println は、渡された引数を保持しない組み込み関数です。その結果、引数はヒープにエスケープされず、スタック上に割り当てられます。一方、

fmt.Println は標準ライブラリからのものであり、カスタム関数のように扱われます。コンパイラは、fmt.Println が引数を保持しないことを想定していないため、引数がヒープにエスケープされる可能性があります。その結果、fmt.Println への引数はスタックではなくヒープに割り当てられます。

stackCopy 関数は大きな引数 ([size]int) を取るため、初期スタックが不十分になる可能性があり、より大きなスタックが必要になります。割り当てられました。スタック上に割り当てられた変数がヒープにエスケープできる関数に引数として渡される場合、スタックの成長に応じて変数はヒープに移動されます。これが、println のみが使用されている場合に s のアドレスの変化を観察する理由です。

結論

println と fmt.Println を混合すると、次の理由によりスタックの増加に影響を与える可能性があります。彼らの議論の扱い方の違い。 println は引数をスタックに保持しますが、fmt.Println は引数をヒープに割り当てる可能性があるため、スタック レイアウトや変数アドレスが変更される可能性があります。

以上が`println` と `fmt.Println` を混在させると Go のスタックの増加に影響を与えるのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。