2011-12-23 17 views
6

をクラッシュテストプログラム私はちょうど約K & Rを読み終えています、そしてそれは私が知っているすべてのCです。すべての私のコンパイルは、MinGWを使ってWindowsのコマンドラインから実行され、私は高度なデバッギング方法について知りません(したがって、私の第2プログラムの "ゲットーデバッグ"のコメント)。理解メモリの割り当て、

私は私がより良い方法をメモリ割り当ての動作を理解するためのいくつかの小さなテストプログラムを作成しようとしています。これらの最初のカップルプログラムはmallocまたはfreeを使用していないので、関数へのローカルな標準配列のメモリの割り当てと割り当て解除を見たいと思っています。私が実行しているプロセスのRAM使用量を見て、それが私が理解しているものと一致するかどうかを確認することです。以下のこの最初のプログラムでは、期待どおりに動作します。 alloc_one_meg()関数は、250,000の4バイト整数を割り当てて初期化しますが、関数が戻るとすぐにMBが割り当て解除されます。したがって、その関数を1000000回連続して呼び出すと、RAM使用量が1MBを大きく上回ることはありません。そして、それは動作します。以下、この2番目のプログラムのために

#include <stdio.h> 
#include <stdlib.h> 

void alloc_one_meg() { 
    int megabyte[250000]; 
    int i; 
    for (i=0; i<250000; i++) { 
     megabyte[i] = rand(); 
    } 
} 

main() 
{ 
    int i; 
    for (i=0; i<1000000; i++) { 
     alloc_one_meg(); 
    } 
} 

、アイデアは、関数が、私は再帰で実現一度に実行されている同じ機能の1000のコピーを、持っているために、終了することができませんでした。私の理論では、再帰が終了した後にプログラムをすべて割り当て解除する前に、プログラムが1GBのRAMを消費するというものでした。しかし、再帰によって2番目のループを通過することはありません(私のゲットーデバッグのコメントを参照してください)。プログラムはかなり有益ではない(私にとっては)メッセージ(Windowsのポップアップで____、exeが問題に遭遇しました)でクラッシュします。通常、私はゲットーデバッグメソッドを使って、常に物事の底を知ることができます...しかし、ここでは機能しません。私は困惑している。このコードの問題は何ですか?ありがとう!

#include <stdio.h> 
#include <stdlib.h> 

int j=0; 

void alloc_one_meg() { 
    int megabyte[250000]; 
    int i; 
    for (i=0; i<250000; i++) { 
     megabyte[i] = rand(); 
    } 
    j++; 
    printf("Loop %d\n", j); // ghetto debug 
    if (j<1000) { 
     alloc_one_meg(); 
    } 
} 

main() 
{ 
    alloc_one_meg(); 
} 

フォローアップの質問here

+2

これでスタックオーバーフロークラッシュが発生したため、メモリの理解を深めることができました。面白いようなことがそのように動作する方法。 –

+2

私はプログラミングが初めてですが、テストのアイデアには新しいことはありません。私はエンジニアであり、重いソフトウェアユーザであり、壊れていることがそれらを理解する最善の方法であることをよく知っています! :-) – The111

答えて

3

スタックオーバーフローが発生しています。

ローカル自動ストレージ変数は(例えばmegabyteような)空間の量を制限しているスタック上に割り当てられています。 mallocはヒープに割り当てます。これにより、より大きな割り当てが可能になります。

あなたがここで詳細を読むことができます:

http://en.wikipedia.org/wiki/Stack_overflow

(私はメモリが割り当てられている場合、C言語が指定されていないことに注意しなければならない - スタックとヒープは、実装の詳細です)

+4

どのようにクール、私はstackoverflow.comでスタックオーバーフローについて学んだ。私はメタにこれを投稿する必要があります!説明とリンクをありがとう。 – The111

+0

malloc()にはより多くの領域がありません - dumpbinの出力と "heap"の予約量を​​参照してください。 –

2

の大きさをWindowsプログラムのスタックは通常約1 MBなので、2回目の再帰ではスタックがあふれてしまいます。

void alloc_one_meg() { 
    int *megabyte = malloc(sizeof(int) * 250000); // allocate space for 250000 
                // ints on the heap 
    int i; 
    for (i=0; i<250000; i++) { 
     megabyte[i] = rand(); 
    } 
    j++; 
    printf("Loop %d\n", j); // ghetto debug 
    if (j<1000) { 
     alloc_one_meg(); 
    } 

    free(megabyte); // DO NOT FORGET THIS 
} 

言った:あなたがスタック上に、このような大きな配列を割り当てるべきではありません、割り当て、ヒープ上のメモリを解放するためにmallocfreeを使用します(配列の、このような大きさの周りmallocを取得する方法はありません)実際にはプログラムのスタックサイズを変更してサイズを大きくすることができます(ただし、プロダクションコードではなく、教育的な練習としてのみ行います)。 Visual Studioの場合はuse the /F compiler option、Linuxの場合はsetrlimit(3)を使用できます。私はMinGWで何を使うべきか分かりません。

+0

彼はmalloc/freeを使いたくないと言った。 – Pubby

+2

@Pubby彼はそれらを使用することはできません –

+0

この一連のテストの大きな目的の一部は、mallocの目的を理解するのを助けることでした。私は最初にいくつかのテストを実行したかったのですが、その後いくつかのテストを実行したかったのです。ヒープ変数はmalloc/freeに関連していましたが、ローカルスタック変数には関数の入力/終了に関連する人生があることは知っていましたが、スタックにこのような小さな制限があることはわかりませんでした。だから私はすでにこのテストで大きなことを学んだ。 :-) – The111

0

StackOverflow。これはトリックの質問ですか?

+0

いいえ、私はちょうどnoobです。私はK&Rから得ることができないことを知る必要があることについて、Cについてたくさんあることを非常に素早く学んでいます(私が言ったように、これまでの唯一の知識源です)。私にそのような質問をすることを妨げていた知識について知る良い場所はどこですか?スタック/ヒープ、そのようなもの(それらの概念はK&Rには存在しません。なぜそれが実現するのでしょうか)。 – The111

1

あなたは再帰関数呼び出しによって割り当てているメモリは、スタックから割り当てられます。すべてのスタックメモリは連続していなければなりません。プロセスがスレッドを開始すると、Windowsはそのスレッドのスタックの仮想メモリアドレス空間の範囲を予約します。予約されるメモリの量は、EXEファイルの "PEヘッダ"で指定されます。 PEは「Portable Executable」の略です。そして、そこにいくつかの出力があり、そして...

dumpbin /headers dumpbin.exe

 100000 size of stack reserve 
     2000 size of stack commit 

dumpbinユーティリティを使用して

は、入力ファイルとして自分自身とのVisual Studio、(dumpbin.exe)に含まれています「100000」はの16進数で1,048,576に等しいので、これは約1MBを表します。

つまり、オペレーティングシステムは1MBのアドレス範囲しか予約しません。そのアドレス範囲が使い尽くされると、Windowsはスタックを増やすために連続したメモリ範囲をさらに割り当てることができます。結果は、さらに隣接するアドレス範囲が使用可能かどうかによって異なります。スレッドが開始されたときにWindowsが行った他の割り当てのために、利用可能性は非常に低いです。

Windowsで最大限の仮想メモリを割り当てるには、VirtualAllocファミリの機能を使用します。