メモリ内のアドレスを一定に保ちたいGoオブジェクトがあります。C#では、オブジェクトの場所をメモリに固定できます。Goでこれを行う方法はありますか?
2 に答える
参照を保持しているオブジェクトは移動しません。ハンドルや間接参照はなく、取得するアドレスは永続的です。
ドキュメントから:
Cとは異なり、ローカル変数のアドレスを返すことはまったく問題ないことに注意してください。変数に関連付けられたストレージは、関数が戻った後も存続します
変数を設定すると、演算子を使用してこのアドレスを読み取り、&
渡すことができます。
tl; dr no-しかし、何か変わったことをしようとしているのでない限り、それは問題ではありません。
受け入れられた答えが部分的に間違っていることに注意する価値があります。
オブジェクトがスタック上またはGoヒープ上で移動されないという保証はありませんがunsafe
、Goランタイムがポインタを透過的に更新する場合に備えて、これを使用しない限り、これは重要ではありません。オブジェクトが移動します。
OTOHを使用unsafe
してuintptr
、生のsyscallを呼び出したり、CGO呼び出しを実行したり、その他の方法でアドレス(たとえばoldAddr := fmt.Sprintf("%p", &foo)
)を公開したりする場合は、アドレスが変更される可能性があり、コンパイラもランタイムも魔法のようにパッチを適用しないことに注意してください。
現在、標準のGoコンパイラはスタック上のオブジェクトのみを移動しますが(たとえば、ゴルーチンスタックのサイズを変更する必要がある場合)、Go言語仕様には、別の実装がGoヒープ上のオブジェクトを移動することを妨げるものはありません。
スタックまたはGoヒープにオブジェクトを固定することは明示的にサポートされていませんが、推奨される回避策があります。Goヒープの外部にメモリを手動で割り当て(たとえば、経由でmmap
)、ファイナライザーを使用して、すべての参照が割り当てられたら、その割り当てを自動的に解放します。ドロップされます。このアプローチの利点は、Goヒープの外部に手動で割り当てられたメモリが、Goランタイムによって移動されないため、アドレスが変更されることはありませんが、不要になったときに自動的に割り当てが解除されるため、リークが発生しないことです。 。