あなたに次の選択肢を用意するサイト
Thoth Coworker
~ プログラミングの次++ ~
For
新社会人 / 新学生 / 新院生 / 新研究者
カテゴリ
ヒープ、スタックを知る
Facebookシェア Twitterツイート LINEで送る
P
ポイント
ヒープ、スタックを知る
プログラム実行時に使われるヒープとスタックについて学ぶための記事
  • Point 1
    ヒープを知る
    ヒープはnewやdeleteのような関数で実行時にデータを置く場所をメモリに用意(確保)するときに使用します.データのサイズを考慮してデータ置く場所が選択され、不要になったデータから解放されます
  • Point 2
    ヒープで起きる問題
    データの確保や解放する順序に制限がないため、メモリ上に使えるメモリがばらけてしまいます(フラグメンテーション).データの大きさによっては置けなくなることも考えられます.
  • Point 3
    スタック
    スタックは与えられたメモリの末尾から順番に使用(確保)され逆順に解放されます.順番の制限により効率的にメモリを使用できます.
P
ステップ概要
ヒープ、スタックを知る
まずそもそもプログラムがどう動くのかについて簡単にまとめます
プログラムが実行中にどのようなメモリをどう使うのかを解説します
ヒープの意味とその動きや管理のされ方について解説します.
スタックの意味とその動きや管理のされ方について解説します.
Step
1
プログラムの動きを知る
スタックやヒープを理解するために、プログラムの動きについて簡単に紹介します.
詳細は下記のリンクを確認してください.
プログラムの動きを知る
プログラムがどのような処理をしながらどういった動きをしているのかについて簡単に解説します.
リンク
プログラムの動きのポイントを箇条書きにします.
ポイント : プログラムの動き
  • プログラムが与えられたメモリ上にロード
  • プログラムが自由に与えられたメモリを使用
  • はじめの関数から順番に関数を実行
  • 次の関数を呼んだら今の関数や変数の状態は一時保存しておき後で関数から戻ったときに復元
プログラムは決まったサイズの与えられたメモリを使うことができます.また、基本的にプログラムがこのメモリをどうやって使うかを決めることができます.

プログラム(および呼ばれる関数)を実行するためにはそのプログラムのコードデータを必ずメモリにロードしておく必要があり、その他プログラムが動く時には"プログラムが処理する画像や音声、テキストデータ"も"今の変数の状態"もすべてそのメモリの上で処理しなくてはなりません.(メモリの外にファイルとして置くこともできます)
画像 : プログラムは与えられたメモリの中でやりくり

プログラムは関数から関数を呼び出して様々な処理を実行します.その際、関数を呼び出し終わって呼び出し元の関数に戻ってくる時には"元々の呼び出し元の関数は何だったか"や"元の関数を実行していたときのそれぞれの変数の値はいくつだったか"を覚えておく必要があります.プログラムはそれらを関数を呼ぶ時にメモしています.
画像 : 呼ばれた関数をメモしながら次の関数へ
Step
2
プログラムが使うメモリを知る
先ほども書いたようにプログラムは与えられたメモリを自身でどう使うか決めます.
多くの場合、メモリの使い方の区分としてはプログラムを置くための「テキスト領域」、グローバル変数などを置く「データ領域」、今回学ぶヒープやスタックがあります.
これらのアドレスの使用状況はプログラムが管理しそれぞれの領域がどれほど使われているかを実行しながら把握しています.

画像 : プログラムの主なメモリの使用区分
プログラムの大きさやグローバル変数などに関してはプログラムを実行する前にプログラムを作った時点で既に決まっています.しかし、ヒープとスタックはプログラムを動かさないとどれほどの大きさになるかわからないため上記のような配置で、大きさを変えられるようになっています.

Step
3
ヒープの動きを知る
それではヒープについての解説になります

ヒープはC言語でのmallocやfreeの関数を使用した時などに使われます.
malloc(size)はメモリの確保をする関数で、プログラムを実行中に必要な大きさが決まりそれを確保するときに使用されます. もし、あらかじめ100個分の配列データが必要といったように大きさが決まっているのであれば、mallocを使う必要はありません.基本的にmallocは10人分のデータが必要だったり50人分のデータが必要だったりと、実行されたときになって初めて大きさが決まるデータを確保するのに使用します.

データに高速にアクセスするためにはデータを連続したメモリに確保する必要があります.ヒープでは様々な大きさのデータが確保され、そのサイズが連続して置ける場所を見つけて置かれます.解放する順番も決まっていないため、場合によっては歯抜けのような状態になります.その状態をフラグメンテーション(断片化)と呼びます.フラグメンテーションになった場合には、最悪ヒープが確保できなくなってしまいます.

画像 : ヒープとmalloc/free
ヒープを使う時はプログラムでどこが空いていてどこが使われているかを全て管理しています.その管理のためのアルゴリズムも様々提案されており、doug Leaのmalloc(dlmalloc)などが有名です.
Step
4
スタックの動きを知る
それではスタック領域についてです.

スタック領域はプログラムの状態を退避しておくときなどに使用されます
先ほど説明したようにプログラムは次から次へと関数を呼び出して実行していきます
そのため戻ってくるべき関数やその関数での状態を覚えておかなくてはなりません.
それをデータとして置いておくのがスタック領域になります

スタック領域はメモリの端から順番にメモリを使っていきます.
スタック領域は関数を呼び出した順番に呼び出した関数や変数の値をデータとしてメモリに隙間なく積んでいき、最も上に積んだデータから消していきます(先入れ後出し/First In Last Out /FILO).隙間なくデータを積んで消すことができるため、ヒープで起きたような断片化は起こりません.

先ほどの例をスタックに置き換えて表現すると以下のようになります.
画像 : 関数呼び出しとスタック
よく聞く「スタックオーバーフロー(スタックバッファオーバーフロー)」はスタック領域が大きくなりすぎてヒープ領域や他のメモリ領域にはみ出し破壊するような状態を指します.
画像 : スタックオーバーフロー
Done