私が見たすべてのプログラムは、データメモリを1つ以上の呼び出しスタック(通常は固定サイズですが、そうでない場合もあります)、ヒープ、および静的メモリに編成します。最近、スレッドローカルの静的ストレージもこれに追加されました。
コールスタックなしなど、根本的に異なる方法でデータメモリレイアウトを整理する試みはありますか?または、同じことを達成する別の方法でメモリを整理しますか?
私が見たすべてのプログラムは、データメモリを1つ以上の呼び出しスタック(通常は固定サイズですが、そうでない場合もあります)、ヒープ、および静的メモリに編成します。最近、スレッドローカルの静的ストレージもこれに追加されました。
コールスタックなしなど、根本的に異なる方法でデータメモリレイアウトを整理する試みはありますか?または、同じことを達成する別の方法でメモリを整理しますか?
回答:
一歩下がって、それらの既存のモデルがどこから、そしてなぜ由来するのかを確認したい場合があります。プロセスが作成されると、単純に0からNまでのインデックスが付けられたフラットなストレージ領域が与えられます。このストレージ領域(ここではRAMについて話しています)は専用ハードウェアといくつかの豪華な半導体によって支えられているため、かなり高速です。しかし、それだけではありません。ハードドライブなどの他のデバイスは本質的に同じものであり、インデックスでアドレス指定可能なフラットスペースですが、何桁も遅くなります。
「ヒープ」が存在する理由は、各アプリケーションが単独でRAMの使用を管理しようとすることは非現実的であるためです。昔、それはまさにそれが起こった方法でした、プログラマーは各RAMの場所が何のために使用されるかを正確に事前に計画しました。ソフトウェアがより複雑になると、誰かがブラックボックスに行って「10バイトが必要なので、ギミー」と言って、それらの10バイトの場所や方法の複雑な詳細すべてを心配する必要がないといいのではないでしょうか。それらがどのように回収されるか それがヒープとは何か、それ以上に基本的なことはありません。
スレッドが作成されるたびに、いくつかのデータ構造(およびスタック)が存在します。これらは、今説明したのと同じ "gimme操作"を使用して取得されます。関数呼び出しスタックフレームとLIFOの性質に完全に適合するため、ほぼ普遍的に使用されるスタック。理論的には、各関数の呼び出しとローカル変数をヒープに割り当てることができますが、スタックポインター(x86のESP)レジスターを更新するために必要ないくつかのアセンブリー命令と比較すると、コストがかかりすぎます。
スレッドローカルストレージ(TLS)もヒープの上に構築されます。スレッドが作成されると、管理構造にメモリを割り当てるためのヒープへの移動の一環として、TLSの別のスペースもヒープから割り当てられます。
つまり、結局のところ、実際に持っているのは汎用メモリアロケータ(つまり、ヒープ)だけであり、それ以外はすべてその上に特化したフォームです。言い換えれば、「好きなだけ(または少ない)割り当てたい、好きなだけそれを保持し、好きなときに解放したい」という側面を放棄しても構わないとしたら、取引を回避できます。速度を提供するが、他のいくつかの制限を犠牲にする別のモデルの汎用ヒープアロケーターをオフにします。
スタックを取る。ヒープと比較すると非常に高速ですが、2つのトレードオフが1)メモリが解放されるタイミングを制御できません。代わりに、関数が終了すると、割り当てたものはすべて失われ、2)スタックのサイズは一般に制限されているため、大量のデータをスタックに直接割り当てる場合は注意が必要です。
別のタイプの「メモリモデル」は、システムコールを介してほぼすべての主要なOSによって提供される仮想メモリマネージャ(VMM)です。VMMはヒープに非常に似ています。つまり、任意の量のメモリを要求し、必要なだけそれを保持できるという意味です。ただし、メモリを割り当てることができるのはページサイズの倍数(4 KBなど)に限られるため、VMMを直接使用すると、一度に8〜24バイトを割り当てることが多い一般的なアプリケーションで多くのオーバーヘッドが発生します。実際、ほとんどすべてのヒープの実装は、VMMの上に構築されており、特に、非常に一般的で、特殊化されていない、小さなブロックの割り当てを可能にするためです。ヒープは、より多くのメモリが必要になるとVMMに移動し、そのメモリの多くの小さなチャンクをアプリケーションに割り当てます。
大きなブロックを割り当てる必要があるアプリがある場合は、VMMに直接移動することを検討してください。ただし、一部のヒープにはmalloc()内にifステートメントがあり、ブロックサイズがしきい値より大きい場合は、VMMに移動しますあなたのために。
ヒープを直接使用する代わりのアロケータの別の形式は、プールです。プールは、すべてのブロックが同じサイズである特殊なアロケーターです。プール(スタックやTLSと同様)は、ヒープまたはVMMの上に構築されます。プールは、同じサイズの短期間の多数のオブジェクト(数百万)を割り当てる場合に役立ちます。着信要求を処理するネットワークサービスを考えてください。各クライアント要求により、その要求を処理するために同じNバイト構造が割り当てられる可能性があります。プールの使用とのトレードオフは、各プールが1つのブロックサイズしか処理しないことです(ただし、複数のプールを作成できます)。プールの利点は、すべてのオブジェクトが同じサイズであるため、複雑なロジックを必要としないことです。代わりに、新しいブロックが必要なときはいつでも、最近解放されたブロックが提供されます。
最後に、上で述べたハードドライブのことを覚えておいてください。ファイルシステムのように動作し、ディレクトリエントリとiノードの同じアイデアを複製して、各データブロックがパスでアドレス指定されるデータブロックの階層的な割り当てを可能にするメモリモデルを使用できます。それこそがtmpfsが行うことです。
私が言及したもの以外にも、私は他のより専門的なモデルがあると確信していますが、結局のところ、すべてがフラットなアドレス空間に基づいているためです(ある種の奇妙なものが何らかの奇妙な$$の非フラットな空間を生み出すまで) )、それはすべて、VMMまたはヒープのいずれかであるその一般的な「gimme」アロケーターに戻ります。
私が考えることができる唯一のケースは、メモリ内の固定された場所ですべてを実行している可能性がある特殊なハードウェアの場合です。完全に柔軟なプログラムが必要な場合は、現在のメモリモデルのほとんどすべてが必要です。
スタックがないと、ローカル変数、コールスタックなどを持つことができません。実装するために作成した他のものは、スタックとよく似たものになります。
静的メモリと、特定のアプリケーションでドロップする可能性のあるヒープですが、さらに高度な処理を行うには、何らかの形でそれらを戻す必要があります。
したがって、これら3つのうちの1つを置き換えるために発明したものは、最終的にはこれら3つのうちの1つによく似たものになります...
別の角度からアプローチするために、何が新しく追加されますか?グラフィックス/物理プロセッサ/ CPUキャッシュなどのようなものは新しいメモリの場所であると主張する可能性がありますが、実際には、それらは単に別のインスタンスであるか、既存のモデルへのアクセスを高速化する方法です。
...誰かが何らかの概念的な飛躍を思いつくまでは、この領域に大きな変化が長期的に見られることはないと思います...