2012-09-19 14 views
5

私はこれらのコンセプトに非常に新しいですが、私はあなたにすべての質問をしたいと思います。私は思っていますが、混乱しています。 質問は... OSによってプロセスのサイズがどのように決まるのですか? まずCプログラムを書いたとしたら、どれくらいのメモリが必要なのかを知りたいのですが、どのように決定できますか?第二に私は、コードセクション、データセクション、プロセスのBSSのような多くのセクションがあることを知っています。今、これらのサイズはあらかじめ決められていますか?第2に、スタックとヒープのサイズがどのように決定されるか。プロセスの合計サイズが計算されている間はスタックとヒープのサイズも重要です。プロセスサイズの決定方法は?

プログラムをロードすると、アドレス空間がプロセスに与えられます(つまり、ベースレジスタとリミットレジスタによって行われ、MMUによって制御されます)。プロセスがメモリ位置にアクセスしようとするとそのアドレス空間にない場合、セグメント化エラーが発生します。どのようにして、プロセスがそのアドレス空間にないメモリにアクセスすることが可能か。私の理解によると、バッファオーバーフローが発生すると、アドレスが破損します。プロセスが破損した場所にアクセスしたい場合、セグメンテーション違反が発生します。住所違反の他の方法はありますか?

なぜスタックが下向きになり、上向きにヒープするのですか?このプロセスはすべてのOSで同じです。パフォーマンスにどのような影響を与えますか。なぜ他の方法で使用できないのでしょうか?

いずれかの記載が間違っている場合は、私を修正してください。

おかげ Sohrab

+0

プログラミングに関する質問ではありません。 – unwind

答えて

1

プロセスが開始されると、プロセスは自身の仮想アドレス空間を取得します。仮想アドレス空間のサイズは、オペレーティングシステムによって異なります。一般に、32ビットプロセスでは4 GiB(4ギガバイナリ)アドレスが得られ、64ビットプロセスでは18 EiB(18 exaバイナリ)アドレスが得られます。

仮想アドレススペースにマップされていないものには、決して定義されていないものはアクセスできません。そこにマップされていないものにはアドレスはありません。あなたは現在何にもマップされていない仮想アドレス空間の領域にアクセスしようとするかもしれません。その場合、segfault例外が発生します。

アドレス空間のすべてが、ある時点で何かにマッピングされているわけではありません。また、すべてがマップされているわけではありません(マップされるマップの量は、プロセッサーとオペレーティングシステムによって異なります)。現在の世代のIntelプロセッサでは、アドレス空間の最大256 TiBがマッピングされます。オペレーティングシステムはこれをさらに制限する可能性があることに注意してください。たとえば、32ビットプロセス(最大4つのGiBアドレスを持つ)の場合、Windowsはデフォルトでシステムに2 GiB、アプリケーションに2 GiBを予約します(ただし、システムに1 GiB、アプリケーションに3 GiBにする方法があります)。

アプリケーションの実行中に変更されるアドレス空間の量と変更量。オペレーティングシステム固有のツールを使用すると、現在割り当てられているメモリと仮想アドレス空間が実行中のアプリケーションのものであるかどうかを監視できます。

コードセクション、データセクション、BSSなどは、リンカーによって作成された実行可能ファイルのさまざまな領域を参照する用語です。一般に、コードは、静的に割り当てられるが変更可能なデータとは別の静的な不変データとは別個のものである。スタックとヒープは、上記のものとは別のものです。それらのサイズは、コンパイラとリンカによって計算されます。各バイナリファイルにはそれぞれ独自のセクションがあるので、動的にリンクされたライブラリはアドレス空間に別々にマップされ、それぞれのセクションはどこかにマップされます。ただし、ヒープとスタックはバイナリイメージの一部ではありません。通常、プロセスごとに1つのスタックと1つのヒープがあります。

スタックのサイズ(少なくとも最初のスタック)は一般的に固定です。コンパイラおよび/またはリンカには、通常、実行時に必要なスタックのサイズを設定するために使用できるフラグがいくつかあります。スタックは一般的に「後退する」というのは、それがプロセッサスタック命令の仕組みだからです。スタックが一方向に成長し、残りが成長すると、両方を無制限にしたいが、どれだけ成長できるか分からない状況では、メモリを整理することが容易になります。

ヒープは、一般に、プロセスの開始時に事前に割り当てられていないものを指します。最低レベルでは、ヒープ管理に関連するいくつかの論理操作があります(すべてのオペレーティングシステムでここで説明するようにすべてが実装されているわけではありません)。

アドレス空間は固定されていますが、一部のOSはプロセスによって現在どの部分が再生されているかを把握しています。これが当てはまらない場合でも、プロセス自体はそれを追跡する必要があります。従って、最低レベルの動作は、アドレス空間の特定の領域が使用されることを実際に決定することである。

第2の低レベルの操作は、OSにその領域を何かにマップするように指示することです。これは、一般的に

  • スワップおよびいくつかの他のファイル

    にマッピングされ

  • システムのスワップファイルにスワップとマッピングされたメモリである

  • メモリをスワップに対応していませんいくつかのメモリとすることができます

  • 読み取り専用モードでスワップ可能で、他のファイルにマップされているメモリ

  • 別の仮想アドレス領域が他の仮想アドレス領域をマップする、同じマッピングが

  • 別の仮想アドレス領域をマップする、同じマッピングが

  • にマッピングされたが、読み取り専用モードにあるのと同じマッピングが、デフォルトのスワップファイルにマッピングされたコピーされたデータと書き込みモードのコピーで

は、私が忘れてしまった他の組み合わせがあるかもしれませんが、それらは主なものです。

もちろん、実際に使用されるスペースの合計は、その定義方法によって異なります。現在使用されているRAMは、現在マップされているアドレス空間とは異なります。しかし、私が上記に書いたように、オペレーティングシステムに依存するツールでは、現在何が起きているのかを知ることができます。

1

は、セクションでは、実行可能ファイルによって予め定められています。

これ以外にも、ダイナミックにリンクされたライブラリのライブラリもあります。 DLLのコードと定数のデータは複数のプロセス間で共有され、複数回はカウントされませんが、プロセス固有の非定数データはすべてのプロセスで考慮する必要があります。

さらに、処理中に動的にメモリを割り当てることができます。

さらに、プロセスに複数のスレッドがある場合、それぞれに独自のスタックがあります。

さらに、プロセス自体とカーネルの代わりにスレッド単位、プロセス単位、ライブラリ単位のデータ構造があります(スレッドローカルストレージ、コマンドラインパラメータ、さまざまなリソースへのハンドル、それらのリソースのための構造体など)。

すべてのプロセスがどのように実装されているかを知らずに、完全なプロセスサイズを正確に計算するのは難しいです。あなたは、しかし、合理的な見積もりを得るかもしれません。

W.r.t. According to my understanding when some buffer overflows happens then the address gets corrupted.それは必ずしも真実ではありません。まず第一に、何のアドレス?それは、バッファの近くのメモリに何が起こるかによって異なります。アドレスがある場合、バッファオーバーフロー中に上書きされる可能性があります。しかし、あなたの写真が入っている近くにもう1つのバッファがあると、ピクチャのピクセルが上書きされる可能性があります。

必要な権限がないメモリにアクセスしようとすると、セグメンテーションやページ違反が発生する可能性があります(プロセスアドレススペースにマップされているか、存在しない場合など)。または、読み取り専用の場所にすることもできます。または、その場所に物理メモリへのマッピングを持たせることはできません。

スタックとヒープの位置とレイアウトが、私たちが話していることのパフォーマンスを知らずにパフォーマンスに影響を与えるかどうかを知ることは難しいです。あなたは推測することができますが、推測は間違っていることが判明する可能性があります。

Btwの場合、別の問題については別にSOの質問をすることを検討する必要があります。

+0

ありがとう...次回はそのことを心に留めておきます...:)...説明に感謝します。 –

1

"プロセスがそのアドレス空間にないメモリにアクセスするにはどうしたらよいですか?"

これは不可能です。しかし、が試みられた可能性があります。ランダムポインタまたはバッファを越えたアクセスを考えてください。任意のポインタを十分長くインクリメントすると、マップされていないアドレス範囲に迷い込んでしまうことはほとんどありません。簡単な例:

char *p = "some string"; 

while (*p++ != 256) /* Always true. Keeps incrementing p until segfault. */ 
    ; 

このような単純なエラーはあまり知られていません。

+1

これは「litotes」と呼ばれています。 :) – Mehrdad

+0

ありがとう!私はこの種の用語を学ぶことを全く嫌っていません:-) – Jens

0

#2と#3の質問に答えることができます。

回答#2

Cで、あなたが本当に(現代のOS上の論理アドレス、脚注を参照)、メモリへのアドレスとして解釈された数値を使用しているポインタを使用する場合。あなたはあなたの意志でこのアドレスを変更することができます。値があなたのアドレス空間にないアドレスを指している場合は、セグメンテーション違反があります。

このシナリオを考えてみましょう。あなたのOSは0x01000から0x09000までのアドレス範囲をプロセスに与えます。あなたが指摘したように続いて

int * ptr = 0x01000; 
printf("%d", ptr[0]); // * prints 4 bytes (sizeof(int) bytes) of your address space 
int * ptr = 0x09100; 
printf("%d", ptr[0]); // * You are accessing out of your space: segfault 

は、主にセグメンテーション違反の原因は、NULLへのポインタを使用する(つまり、ほとんどが0x00のアドレスですが、実装に依存)、または破損したアドレスの使用です。

Linuxのi386では、ベースレジスタとリミットレジスタが使用されていないことにご注意ください。それらはプロセスごとの制限ではありませんが、ユーザー空間またはカーネル領域という2種類のセグメントを指しています。

回答#3

スタックの成長は、ハードウェアに依存し、OSに依存しません。 pushとpopのようなi386アセンブリ命令では、スタック関連のレジスタに関してスタックが下に向かって成長します。たとえば、スタックポインタは、プッシュを行うと自動的に減少し、ポップを行うと増加します。 OSはそれに対処できません。現代のOSでは

脚注

、プロセスは、いわゆる、論理アドレスを使用しています。このアドレスは、OSによって物理アドレスとマッピングされます。あなたがこのプログラムを複数回(偶数同時に)あなたも異なるインスタンスのために、見ることが実行した場合

#include <stdio.h> 

int main() 
{ 
    int a = 10; 
    printf("%p\n", &a); 
    return 0; 
} 

、同じアドレスをプリントアウト:この自分でコンパイルし、この単にプログラムのノートを持っています。もちろん、これは実際のメモリアドレスではありませんが、必要なときに物理アドレスにマップされる論理アドレスです。

関連する問題