2012-06-25 24 views
21

私はメモリモデルをもう少し調べていますが、プロセス内にいくつのヒープが存在するかを理解するのに苦労しています。スタックとヒープの割り当て

5つのスレッドで1つのプロセスがある場合は、5つのスタックと1つのヒープを持つと言っても間違いありませんか?

もしそうならば、スレッドは互いのスタックにアクセスすることができますか(つまり、破損を防ぐためにスタックが別々の理由があります)、ちょうど1つのヒープがあれば、明らかにすべてがこのヒープにアクセスします複数のスレッドで?私はこれを正しく理解していますか?

答えて

31

はい、各スレッドには独自のスタックがあります。それは難しいことですが、スタックは、メソッドが終了した後にどこを返すかを追跡し、戻りアドレスを格納します。各スレッドは独自のコードを実行するため、独自のスタックが必要です。ローカル変数とメソッド引数もそこに格納されており、(通常は)スレッドセーフです。

ヒープ数は、より詳細に関係しています。ガベージコレクションされたヒープの数は1です。実装の観点からは完全に正しいわけではありません.3つの世代ヒープとラージ・オブジェクト・ヒープは、論理的に異なるヒープであり、最大4つまで追加します。この実装の詳細は、あまりに多く割り当てると問題になります。

管理対象コードで完全に無視できないもう1つは、静的変数を格納するヒープです。これはAppDomainに関連付けられており、静的変数はAppDomainの存続期間中存続します。一般に、.NETの文献では「ローダーヒープ」と呼ばれています。実際には3つのヒープ(高頻度、低頻度、スタブヒープ)で構成されています。ジッタコードとタイプデータもそこに保存されていますが、それは根強さを増しています。

さらに、無視リストの下には、ネイティブコードで使用されるヒープがあります。そのうちの2つはマーシャルクラスから容易に見える。デフォルトのプロセスヒープがあり、そこからWindowsが割り当てられます。Marshal.AllocHGlobal()も同様です。また、COMがデータを格納する別のヒープがあり、Marshal.AllocCoTaskMem()はそれを割り当てます。最後に、相互運用するネイティブコードには、ランタイムサポートのための独自のヒープがあります。この種のコードで使用されるヒープの数は、プロセスにロードされるネイティブDLLの数によってのみ制限されます。これらのヒープはすべて存在し、あなたはそれらを直接扱うことはほとんどありません。

したがって、最小10ヒープ。

12

つまり、はいです。

プロセス内のすべてのスレッドは同じヒープを共有しているため、データを交換できます。各スレッドには、このスレッドの現在のコード実行に関連する独自のスタックがあります。

スレッドに非常に優れたリソースはここにある:http://www.albahari.com/threading/

スレッドでのご アプリケーションを実行するオペレーティング・システムのプロセスに似ています。プロセスがコンピュータ上で並列に実行されるのと同様に、 スレッドは1つのプロセス内で並列に実行されます。プロセスは完全に互いに分離された です。スレッドは、限定された度合いが の単なる単なるものです。特に、スレッドは、同じアプリケーション内で実行中の他のスレッドと(ヒープ)メモリを共有します( )。これは、部分的に スレッドが便利な理由です.1つのスレッドは、 インスタンスのバックグラウンドでデータをフェッチできますが、別のスレッドは到着時にデータを表示できます。

+1

優れたリンクをお寄せいただきありがとうございます。 – Richard

2

これは実装定義ですが、C#タグを追加するので、最も人気のある最新のOSについて説明しましょう。

プロセス内に存在するヒープの数。

通常、プロセスごとに1つ。

5つのスレッドで1つのプロセスがある場合は、5つのスタックと1つのヒープを持つと言ってもいいですか?

はい。各スレッドは、スレッドスタック用に1MBの仮想アドレス空間をまっすぐに消費します。

、スレッドが互いのスタック(または、彼らは腐敗を防ぐために、別々のスタックを、持っている理由、これは正確である)、そしてちょうど1ヒープがあります場合は、明らかに彼らはすべてこのヒープにアクセスし、それ故に必要性にアクセスできるようにした場合複数のスレッドでロックするには?私はこれを正しく理解していますか?

はい、現代の環境は非常にうまくサンドボックス化されているため、他のスレッドから別のスレッドスタックに直接アクセスすることはできません。

+0

ルーカスはジャック・コネッキーの答えを見た? "どうして他のスレッドスタックにアクセスできないの?"なぜロック機構が存在するのか? – Jasper

+0

このようなダイレクト通信を避け、両方のスレッドからアクセス可能なオブジェクトキューを使用する方が良い方法ですが、確かに別のスレッドのスタックにアクセスできます。 –

+1

Nitpicking:プロセスに(通常の)管理ヒープ、ラージオブジェクトヒープがあり、非管理ヒープを#3と考えることができます。 –

4

スレッドは、単一のプロセスの同じ仮想アドレス空間で同時に実行される個別の命令ストリームです。ヒープは、システムが独自のプライベートな使い方のために各プロセスに与える大きなメモリです。プロセスはヒープサイズを調整することができ、必要とみなしてヒープスペースを使用することができます。スレッドは、このヒープスペースを使用してコラボレーションすることもでき、スレッドローカルストレージ(TLSes)と呼ばれる追加のプライベートメモリ領域を割り当てることもできます。

すべてのスレッドは同じ仮想アドレス空間を共有するため、互いのスタックメモリに直接アクセスできます。これは、あるスレッドが他のスレッドで実行されている関数への引数としてスタック上の変数を渡すことができることを意味します。しかし、まだスレッドスタックは、あるスレッドが別のスレッドのスタックに値をプッシュまたはポップすることはなく、独自のスタック空間にのみポップするという点で、独立しています。 x86とx86-64のスタックは下向きに成長するので、各スレッドのスタックメモリの最下部に特別なページがあります。いわゆるガードページと呼ばれます。スタック障害は、スタックを操作中にガードページに到達した場合に発生します。

CおよびC++のアンマネージ言語では、プロセスメモリのすべての部分に、ポインタの使用によって自由にアクセスできます。 1つのスレッドは、別のスレッドのスタックの内容を完全に混乱させる可能性があり、したがって、2番目のスレッド(およびプロセス全体)がクラッシュします。 C#では、スタックがCLRによって管理されているので、これらの種類のものはunsafeブロックの外側では発生しません。

+0

_oneスレッドは、他のスレッドで実行されている関数への引数としてスタック上の変数を渡すことができます_ –

+0

Win32スレッドでは、新しいスレッドを開始し、現在のスレッドのローカル変数のアドレスをスレッドの引数として渡すことができます。 'PostThreadMessage'を使って、既に実行中のスレッドにメッセージを送ることもできます。 –

+0

どちらの方法もポインタを必要とします。 –

関連する問題