スタック実装の詳細-パート1

画像

少し前に、C#とそのオブジェクトのメモリへの配置に関しては、 「リンク」は「アドレス」ではないと書いた。 これは事実ですが、それは単なる実装の詳細であり、「リンク」の意味ではありません。 要旨と混同されることが多い別の実装の詳細は、「値型のメモリがスタックに割り当てられる」ことです。 私はこれをよく見ます、 なぜならそれが私たちのドキュメントで言っているからです。



私が見るほとんどすべての記事は、スタックが何であるか(しばしば誤って)を詳細に説明し、意味のあるタイプと参照タイプの主な違いは意味のあるタイプがスタックにあることです。 そのような記事の多くの例をネットで見つけることができると確信しています。





観察された動作ではなく、実装の詳細に基づいた重要なタイプの定義は、混乱を招き、完全に正しいものではないと考えています。 重要なタイプのオブジェクトの最も重要な特性は、メモリ内での配置方法ではなく、セマンティクスの観点からの動作方法です。「重要なタイプのオブジェクト」は常に「値によって」送信されます。 コピーされます。 参照型と重要な型の主な違いがメモリ内の場所の詳細にある場合、それらを「ヒープ上の型」と「スタック上の型」と呼びます。 しかし、一般的な場合、これは本質とは関係ありません。 一般的な場合、重要なタイプのインスタンスをどのようにコピーして比較するかが重要です。



残念なことに、ドキュメントは最も重要な機能に焦点を当てていませんが、実装の詳細に焦点を当てており、重要なタイプのポイントを逃しています。 「値によるコピー」とは何か、このメカニズムの誤解がエラーを引き起こす可能性があることを説明する代わりに、「スタックとは何か」を説明するすべての記事を非常に気に入っています。



重要な型がスタックされるというステートメントは、一般的には正しくありません。 MSDNのドキュメントでは、意味のある型がスタックにスタックされることがあると正しく記述されていました。 たとえば、参照型のint型のフィールドは、この型のオブジェクトの一部であり、オブジェクト全体と同様に、そのフィールドはヒープ上にあります。 匿名メソッドの閉鎖に陥るローカル変数(*)と同じ話です。これらは本質的に非表示クラスのフィールドになり、ヒープにも配置されるため、ローカル変数は重要なタイプであってもヒープに配置できます。



つまり、何も説明していない説明があります。 パフォーマンスの考慮事項を破棄すると、開発者の期待という点で、CLRjitterがヒープではなくスタックにint変数を配置する原因になりますか? 何も、仕様に違反するまで、システムは最も効果的なコード生成戦略を選択できません。



ええ、CLIが実装されているオペレーティングシステムが、「スタック」と呼ばれる1メガバイトのサイズの配列を提供すると約束した人はいません。 通常、Windowsはこれを行い、この1メガバイトの配列は、短い寿命の小さなオブジェクトを効率的に保存するのに最適な場所ですが、オペレーティングシステムがこの種の構造を提供したり、ジッターがそれを使用したりする要件や保証はありません。 原則として、Jitterはパフォーマンスの低下にもかかわらずヒープ上にすべてのローカル変数を作成することを決定できます。これは、意味のある型のセマンティック要件が満たされている限り機能します。



意味のあるタイプは「高速で小さく」、参照タイプは「大きく低速である」と考えるのはさらに悪いことです。 実際、スタック上のコードへのジッターによって重要なタイプが生成される可能性があります。これは、メモリの割り当て時とクリア時の両方で非常に高速です。 しかし同時に、重要な型の要素の配列など、ヒープ上に作成された大きな構造体も、デフォルト値で初期化されていれば非常に迅速に作成されます。 また、参照型は余分なメモリ領域を占有します。 そしてもちろん、重要なタイプがパフォーマンスを大幅に向上させる条件があります。 しかし、ほとんどのプログラムでは、ローカル変数の作成と破棄の方法がパフォーマンスのボトルネックになることはありません。



参照タイプを数ナノ秒の意味のある賞金に変換するためのナノ最適化は価値がありません。 これは、参照型の代わりに意味のある型を使用することで解決できる実際の問題があることをプロファイラーデータが示している場合にのみ行う必要があります。 私はそのようなデータを持っていません。 参照型または意味のある型を使用することを選択する場合、作成する型が意味的にどのように動作する必要があるかによって常にガイドされます。



(*)反復子ブロックの場合はtrueです。



翻訳者から:最近、何度かインタビューを行う機会がありましたが、「意味のある参照タイプとは何か」という質問にしばしば答えました。「意味のあるタイプとは、インスタンスがスタック上にあるタイプであり、参照タイプは、インスタンスがヒープ。」 したがって、ここでは、その関連性を失っていない、エリック・リッパートによる非常に古い記事の翻訳があります。 翻訳を可能な限りロシア語で読みやすく、読みやすいものにしようとしたので、意味は違いますが、形は元のものと大きく異なります。



All Articles