すべての.netブックは、値型と参照型について述べており、各型が格納されている状態(ヒープまたはスタック)を(多くの場合は誤って)示すようにしています。通常、最初の数章にあり、非常に重要な事実として提示されます。認定試験でもカバーされていると思います。スタックとヒープが(初心者).Net開発者にとっても重要なのはなぜですか?ものを割り当てると、それは機能します。
すべての.netブックは、値型と参照型について述べており、各型が格納されている状態(ヒープまたはスタック)を(多くの場合は誤って)示すようにしています。通常、最初の数章にあり、非常に重要な事実として提示されます。認定試験でもカバーされていると思います。スタックとヒープが(初心者).Net開発者にとっても重要なのはなぜですか?ものを割り当てると、それは機能します。
回答:
私は、この情報が重要だと考えられる主な理由は伝統だと確信しています。 管理されていない環境では、スタックとヒープの区別が重要であり、使用するメモリを手動で割り当てて削除する必要があります。現在、ガベージコレクションが管理を行っているため、そのビットは無視されます。どのタイプのメモリが使用されているかを気にする必要がないというメッセージが本当に伝わったとは思いません。
Fedeが指摘したように、Eric Lippertはこれについて非常に興味深いことを言っています:http : //blogs.msdn.com/b/ericlippert/archive/2010/09/30/the-truth-about-value-types.aspx。
その情報に照らして、私の最初の段落を調整して、基本的に読むことができます:「人々がこの情報を含めて重要だと考える理由は、過去にこの知識を必要とすることと組み合わされた不正確または不完全な情報のためです」
パフォーマンス上の理由でそれがまだ重要だと思う人のために:物事を測定し、それが重要であることがわかった場合、ヒープからスタックに何かを移動するためにどのようなアクションを取りますか?おそらく、問題領域のパフォーマンスを改善するまったく異なる方法を見つけるでしょう。
すべての.NETブックは値型と参照型について述べており、各型が格納されている状態(ヒープまたはスタック)を(多くの場合は誤って)示すようにしています。通常、最初の数章にあり、非常に重要な事実として提示されます。
私は完全に同意します。私はいつもこれを見ています。
.NETブックでスタックとヒープメモリの割り当てについて説明しているのはなぜですか?
その理由の1つは、多くの人がCまたはC ++のバックグラウンドからC#(または他の.NET言語)に来たためです。これらの言語はストレージの有効期間に関する規則を強制するものではないため、それらの規則を理解し、それらに従うためにプログラムを慎重に実装する必要があります。
さて、これらのルールを知っており、Cでそれらに従うことは、「ヒープ」と「スタック」を理解することを必要としません。しかし、データ構造がどのように機能するかを理解していれば、多くの場合、ルールを理解して従う方が簡単です。
初心者向けの本を書くとき、著者が概念を学んだのと同じ順序で説明するのは自然です。それは必ずしもユーザーにとって意味のある順序ではありません。私は最近、Scott DormanのC#4初心者向け書籍のテクニカルエディターでした。私が気に入った点の1つは、Scottがメモリ管理の実際の非常に高度なトピックから始めるのではなく、トピックのかなり賢明な順序を選択したことです。
理由の別の部分は、MSDNドキュメントの一部のページがストレージの考慮事項を強く強調していることです。特に古いMSDNドキュメントは、まだ初期の頃から残っています。そのドキュメントの多くには、これまでに削除されたことのない微妙なエラーがあり、履歴の特定の時間に特定の対象者向けに作成されたことを覚えておく必要があります。
スタックとヒープが(初心者).NET開発者にとって重要なのはなぜですか?
私の意見では、そうではありません。理解する必要があるのは、次のようなものです。
等々。
ものを割り当てると、それは機能します。
それが理想です。
今、それが重要な状況があります。ガベージコレクションはすばらしく、比較的安価ですが、無料ではありません。小さな構造をコピーすることは比較的安価ですが、無料ではありません。収集圧力のコストと過剰なコピーのコストのバランスを取る必要がある現実的なパフォーマンスシナリオがあります。これらの場合、関連するすべてのメモリのサイズ、場所、および実際の有効期間を十分に理解しておくと非常に役立ちます。
同様に、スタック上にあるものとヒープ上にあるもの、およびガベージコレクターが移動できるものを知る必要がある現実的な相互運用シナリオがあります。そのため、C#には「fixed」、「stackalloc」などの機能があります。
しかし、これらはすべて高度なシナリオです。理想的には、初心者プログラマーはこのようなことを心配する必要はありません。
皆さんはポイントを逃しています。スタック/ヒープの区別が重要である理由は、スコープのためです。
struct S { ... }
void f() {
var x = new S();
...
}
いったんxがスコープ外になる、作成されたオブジェクトは断固れてしまっ。それは、ヒープではなくスタックに割り当てられているためです。メソッドの「...」部分には、その事実を変更できるものは何もありませんでした。特に、割り当てまたはメソッド呼び出しは、S構造体のコピーを作成するだけで、生き続けるための新しい参照を作成することはできませんでした。
class C { ... }
void f() {
var x = new C();
...
}
まったく違うストーリー!xはヒープ上にあるため、そのオブジェクト(つまり、オブジェクトのコピーではなく、オブジェクト自体)は、xがスコープ外になった後も存続し続けることができます。実際、それが存続しない唯一の方法は、xが唯一の参照である場合です。「...」部分の割り当てまたはメソッド呼び出しが、xがスコープから外れるまでに「生きている」他の参照を作成した場合、そのオブジェクトは生き続けます。
これは非常に重要な概念であり、「何となぜ」を本当に理解する唯一の方法は、スタックとヒープの割り当ての違いを知ることです。
...
引き起こす可能性がx
コンパイラ生成されたクラスのフィールドに変換されるので、指示された範囲アウトラスト。個人的には、暗黙のホイストの考えに嫌気がさしますが、言語デザイナーはそれを好むようです(ホイストされる変数に宣言で何かを指定して要求するのではなく)。プログラムの正確性を確保するために、オブジェクトに存在する可能性のあるすべての参照を考慮する必要がしばしばあります。ルーチンが戻るまでに、渡された参照のコピーが残っていないことを知っておくと便利です。
structType foo
、保管場所は、foo
そのフィールドの内容を保持しています。foo
がスタック上にある場合、そのフィールドも同様です。foo
がヒープ上にある場合、そのフィールドも同様です。場合はfoo
、ネットワークのApple IIであるので、そのフィールドです。対照的に、foo
クラス型である場合、オブジェクトnull
またはオブジェクトへの参照を保持します。クラスタイプfoo
がオブジェクトのフィールドを保持していると言える唯一の状況は、それがクラスの唯一のフィールドであり、それ自体への参照を保持している場合です。
なぜ彼らがこのトピックを扱っているのかについて、@ Kirkはそれが重要な概念であり、あなたが理解しなければならないことに同意します。メカニズムを熟知すればするほど、スムーズに実行される優れたアプリケーションを作成するために、より良いことができます。
現在、Eric Lippertは、ほとんどの著者がこのトピックを正しく扱っていないことに同意しているようです。彼のブログを読んで、内部にあるものを深く理解することをお勧めします。
まあ、私はそれが管理された環境の全体のポイントだと思いました。私はこれを基礎となるランタイムの実装の詳細と呼んでさえいれば、それはいつでも変更される可能性があるので、想定してはいけません。
.NETについてはあまり知りませんが、私が知る限り、実行前にJITされました。たとえば、JITはエスケープ分析を実行できますが、突然、スタック上または一部のレジスターにオブジェクトが存在することになります。これを知ることはできません。
著者がそれを非常に重要だと考えているため、または読者がそうすることを想定しているために、いくつかの本がそれをカバーしていると思います(たとえば、「C ++プログラマーのためのC#」
それにもかかわらず、私は「メモリが管理されている」以上に言うことは多くないと思います。さもなければ、人々は間違った結論を出すかもしれません。
明示的に管理する必要がない場合でも、メモリ割り当てを効率的に使用するには、メモリ割り当ての仕組みを理解する必要があります。これは、コンピューターサイエンスのほとんどすべての抽象化に当てはまります。
それが違いを生むことができるいくつかのエッジケースがあります。デフォルトのスタックスペースは1メガバイトで、ヒープは数ギガです。したがって、ソリューションが多数のオブジェクトを保持している場合は、十分なヒープスペースを確保しながらスタックスペースを使い果たすことができます。
ただし、ほとんどの場合、かなりアカデミックです。
あなたが言うように、C#はメモリ管理を抽象化することになっています。ヒープとスタックの割り当ては、理論的には開発者が知る必要のない実装の詳細です。
問題は、これらの実装の詳細を参照せずに直感的な方法で説明するのが非常に難しいことです。可変の値の型を変更するときの観察可能な動作を説明してください-スタック/ヒープの区別を参照せずに行うことはほとんど不可能です。または、そもそもなぜ言語に値型があるのか、そしていつそれらを使用するのかを説明してみませんか?言語の意味を理解するには、区別を理解する必要があります。
PythonやJavaScriptについての本は、言及すれば大したことではないことに注意してください。これは、すべてがヒープに割り当てられているか、不変であるためです。つまり、異なるコピーのセマンティクスは決して機能しません。これらの言語では、メモリの抽象化が機能しますが、C#ではリークが発生します。