malloc(マロック, エムアロック)、free、calloc、reallocは、動的メモリ確保を行うC言語の標準ライブラリの関数である。codice_1が使用する実際のメモリ確保機構には様々な実装がある。それらの性能は、実行時間と要求されるメモリの両面で様々である。C言語は通常メモリを「静的メモリ確保」か「自動メモリ確保」で管理する。静的変数は主記憶上にプログラムが存在する期間中ずっと確保されている。自動変数(局所変数)は通常コールスタック上に確保され、対応するサブルーチンが実行中の間だけ存在する。しかし、いずれの方法も限界があり、確保できるメモリ量(変数のサイズ)はコンパイル時に決められてしまう。必要なサイズが実行時でないと判明しない場合、例えばディスク上のファイルから任意のサイズのデータを読み込むような場合、固定サイズのデータオブジェクトだけでは不十分である。確保されたメモリの生存期間(使用可能期間)も問題となる。静的でも自動的でも確保されたメモリの生存期間はあらゆる状況に対応できるものではない。スタック上のデータは複数の関数呼出をまたいで持続できないし、静的データは必要かどうかに関わらずプログラムが動作中ずっとメモリ領域を確保し続ける。しかし、そうではなく確保したメモリの生存期間をプログラマが自由に制御できる必要がある場合も多い。これらの制限は動的メモリ確保を使用することで解決する。メモリの管理は明示的に行う必要が出てくるが、柔軟性が向上する。「ヒープ領域」はこのために用意されたメモリ領域である。C言語では、codice_1関数を使ってヒープ領域からメモリブロックを確保する。プログラムはcodice_1の戻り値であるポインタを使って、そのメモリブロックにアクセスする。メモリブロックが不要になったら、そのポインタをcodice_4に渡して解放し、他の用途に再利用できるようにする。ヒープではなくCのスタックフレームから実行時に動的にメモリを確保するライブラリルーチンもある(Unix系の codice_5、Microsoft Windows のCランタイムライブラリの codice_6 など)。このように確保したメモリは呼び出した関数から抜ける時点で自動的に解放される。C99標準で可変長配列がサポートされ、実行時に大きさを決定でき任意の静的スコープの範囲で存在するメモリ確保法が言語構文に組み込まれたが、C11ではサポート必須ではなくオプションに格下げとなった。codice_1はC言語におけるヒープ領域からのメモリ確保に使われる基本関数である。その関数プロトタイプはcodice_8ヘッダに次のように定義されている。ここで、codice_9バイトのメモリが確保される。確保が成功するとそのメモリブロックへのポインタが返される。codice_1が返すのは、void型へのポインタ (codice_11) であり、そのポインタが指す領域のデータ型が不明であることを示している。このポインタは、代入時、暗黙的に型変換され、必要なデータ型へのポインタ型となる。上記のとおりANSI Cにおいては、codice_1のリターン値はcodice_11型なので明示的に変換(キャスト)する必要が無いにもかかわらず、手動での型変換(キャスト)を行う人も存在する。明示的に型キャストする人がいるのは、型が厳密なC++ではエラーになるのと、かつてANSI以前の仕様のCにおいては、codice_1はcodice_15を返していたからである。しかしcodice_8をインクルードし忘れた場合、コンパイラはcodice_1がint型であるとみなす。これをキャストしているとインクルードし忘れたことに気づかないが、キャストしていないとコンパイル時にintをポインタ型変数に代入しようとしているとして何らかのメッセージが表示される。例えば64ビットのシステムでLP64というデータモデルを採用している場合、codice_18とポインタは64ビットだが、codice_19は32ビットとなる。この場合codice_8をインクルードし忘れてそれに気づかないと、codice_1が実際には64ビットのポインタを返すのに、32ビットの値を返すと暗に宣言したことになり、バグが生じる可能性がある。ただし、多くのコンパイラは宣言のない関数を使用していると(キャストの有無に関わらず)コンパイル時に警告を出す。codice_1で確保されたメモリは持続性がある。プログラム終了時か明示的にプログラマが解放しない限り存在し続ける。解放はcodice_4関数で行われる。そのプロトタイプは次のようになる。ここで、codice_24の指すメモリブロックが解放される。codice_1はメモリブロックを確保して返すが、その領域は初期化されていない。必要に応じてメモリは個別に初期化する。例えば、codice_26関数で初期化したり、個別の代入文で初期化する。他にもcodice_27(カロック、シーアロック)関数を使って、メモリ確保と初期化を行うこともできる。そのプロトタイプは以下のようになる。codice_28のサイズのメモリ領域をcodice_29個格納できるメモリ領域を確保する。確保された領域はゼロで初期化される。メモリブロックを大きくしたり小さくしたりできれば便利である。これはcodice_1とcodice_4を組み合わせて、新たなメモリブロックを確保して内容を前のメモリブロックからコピーし、前のメモリブロックを解放することで実現できる。しかし、この方法は回りくどい。代わりにcodice_32(リアロック)関数を使うことが出来る。そのプロトタイプは以下の通りである。codice_32は指定されたサイズのメモリ領域へのポインタを返す。新しいサイズが前のサイズより大きければブロックは大きくされ、逆ならば小さくされる。codice_34はcodice_1とほとんど同じだが、メモリ確保がページ境界になる点が異なる。codice_34で確保された領域へのポインタをcodice_32に渡すことはできない。また、これは標準Cライブラリに含まれる関数ではない。スタック上に10個の整数の配列を作成する一般的な方式は次の通りである:同様の配列を動的に確保するには、以下のようなコードを使うことが出来る。codice_1や関連するC言語の関数の使用はバグの発生源になりやすい。codice_1は必ず成功するとは限らない。利用可能な空きメモリ領域がないとき、プログラムが限界値を超えてメモリを使用しようとしたときなど、codice_1は ヌルポインタを返す。環境によって、このような状況の起きる可能性は異なる。多くのプログラムはcodice_1が失敗することを考慮していない。そのようなプログラムでcodice_1がヌルポインタを返してきたとき、プログラムはNULLに相当するアドレスにアクセスしてクラッシュするだろう。これは昔から設計上のミスとされているが、未だにそのようなプログラムが多い。というのもメモリ確保に失敗するという状況は非常に珍しく、発生した場合には終了する以外にプログラミング上できることがないからでもある。確保失敗をチェックすることはライブラリでは特に重要である。ライブラリはメモリ量が限られた状況でも使用される可能性がある。ライブラリ内でメモリ確保に失敗した場合、呼び出したアプリケーション側にエラーを通知して、アプリケーションプログラムに判断を委ねるのがよいとされる。codice_1で確保したメモリブロックを使用しなくなってもcodice_4で解放せず、次々と新たなメモリブロックを確保していると空きメモリが少なくなってくる。これをメモリリークと呼ぶ。メモリリークによるメモリ消費が無視できない量に達するとページ置換アルゴリズムによってページアウトが発生し、システム性能が低下する。さらに仮想記憶の容量限界に達すると、システム内の他の全プロセスでメモリ確保が失敗してシステムがストールする。メモリリークは、利用のたびにプロセスの起動・終了が行われるプログラムにおいて、特に重要な問題を引き起こさないため、メモリリークが混入した状態で出荷される商用プログラムは多い。しかしながら、連続稼動が要求されるサーバコンピュータ上のプログラム(サービス、デーモン)や、組み込みプログラム等の場合は、メモリリークは死活問題とされる。ポインタがcodice_4に渡された後でその領域への参照を行っても、その内容は未定義であり利用できない。しかし、ポインタ自体が残っていると誤って使ってしまうことがある。次のコードはその例である。このようなコードは予測不能の振る舞いをする。メモリが解放された後でシステムがその領域を他の用途に転用しているかもしれない。従って解放済みメモリ領域へのポインタを使った書き込みはプログラム内の別のデータを不正に書き換えてしまう。どういうデータを書き換えたかによって、その後のプログラムの動作は単なるデータ破壊で済むかもしれないし、クラッシュするかもしれない。特に破壊的なバグとしては、同じポインタを2回codice_4に渡してしまうことで、これを「二重解放; double free」と呼ぶ。これを防ぐため、解放した後でポインタ変数にcodice_47を格納することがある。というのもcodice_48は何もしないことが規格で保証されているからである。ポインタ変数が無効な領域を指しているかどうかを後で調べるときも、codice_47が格納されているかどうかで簡単に判定できるようになる。メモリ管理の実装はオペレーティングシステム (OS) と(ハードウェア)アーキテクチャに大きく依存する。OSによってはmallocのためのアロケータを提供しているし、データ領域の制御関数を提供している場合もある。同じ動的メモリアロケータでmallocだけでなくC++の codice_50 も実装していることが多い。そこでこれを malloc ではなく「アロケータ」と呼ぶ。IA-32アーキテクチャでのアロケータの実装には一般にヒープまたはデータセグメントが使用されている(セグメント方式)。アロケータがメモリを確保するとき、ヒープに未使用領域がない場合はヒープを拡張することでメモリを確保する。ヒープ方式はフラグメンテーションという問題がある。どのようなメモリ確保方式でもヒープではフラグメントが発生する。つまり、ヒープ上に飛び飛びに使用中領域と未使用領域が存在することになる。優秀なアロケータはヒープを拡張する前に未使用領域を再利用しようとする。しかし性能問題があるため、リアルタイムシステムでは代わりに「メモリプール」という方式を使う必要がある(特定サイズのメモリブロックのプールを予め用意しておく方式)。ヒープ方式の欠点は、先頭位置が変更できないため、ヒープの最後の位置に使用中ブロックがある限り、ヒープを縮小することができないことである。従って、このような時は実際に使用しているメモリが少ないのにも関わらず、ヒープのアドレス空間に占める領域が拡大し続けるという問題が生じる。mmapで確保した領域は、縮小したり開放したりすることができる。これらによって開放された領域は、OSのメモリ管理システムに委ねることになる。dlmalloc は Doug Lea が1987年に開発を始めた汎用アロケータ。パブリックドメインライセンス(CC0ライセンス)のオープンソースライブラリ。GNU Cライブラリ (glibc) の malloc は、dlmalloc を元に作られている。ヒープ領域上のメモリは "chunk" という8バイト境界のデータ構造として確保され、その中にヘッダ部と利用可能なメモリがある。chunk および利用中フラグがあるため、8バイトまたは16バイトのオーバヘッドを含めたメモリ確保が必要である。アロケートされていないchunkも他のフリーなchunkへのポインタを持つため、chunkの最小サイズは24バイトとなっている。アロケートされていないメモリは "bin" と呼ばれる同じサイズのchunkのグループに分けて管理される。binはchunkを双方向連結リストで連結したものである。小さな領域 (<256B) を確保するときには2の累乗フリーリストが使われる。領域が不足したときは、より大きなサイズ用の領域からプールを確保する。中程度の大きさの領域は、bitwiseトライ木により管理される。領域が不足したときは、(sbrkによる)ヒープの拡張が行われる。大きな領域(デフォルト値は >= 256KB)は、mmap() が使える環境の場合、mmap() により直接確保される。この大きさならば、ページサイズ(通常4KB, CPUのアーキテクチャに依存する)単位でしか割り当てられないことによるオーバーヘッド、システムコールの遅さによるオーバーヘッドはほとんどない。一方で、先に述べたヒープ方式のアロケーションの問題が起こらないので、この方法が使われる。FreeBSD 7.0以降と NetBSD 5.0以降では、古い実装 (phkmalloc) をJason Evansが開発したjemallocに置換した。phkmalloc はマルチスレッド環境でのスケーラビリティに問題があった。ロックの衝突を防ぐため、jemallocはCPU毎に分離した "arena" と呼ばれる領域を用意する。実験によれば、スレッド数に比例して1秒間のmalloc回数が増えていくとき、phkmallocとdlmallocではスレッド数に反比例した性能を示した。OpenBSDのcodice_1関数の実装はcodice_52を使用している。ページサイズ以上の要求はcodice_52で行われ、ページサイズ未満ならcodice_1内で管理しているメモリプールから割り当てる。そのメモリプールもcodice_52で確保したものである。codice_4を実行すると、codice_57を使ってプロセスのアドレス空間からアンマップされて解放される。このシステムはアドレス空間のレイアウトをランダム化することによってセキュリティを高めるための設計でもあり、OpenBSDのcodice_52が持つギャップページ機能も利用している(mmapで確保した領域が仮想空間上で隣接しないようにする機能)。また、解放後の領域は仮想空間としてマッピングが存在しないため、解放後のアクセスの検出も容易である(普通ならセグメンテーション違反が発生してプログラムが終了する)。は、スケーラブルなメモリ確保性能を目指したアロケータである。OpenBSDのアロケータと同様、Hoard はcodice_52のみを使用するが、64キロバイトのスーパーブロックと呼ばれる塊ごとにメモリを管理する。Hoardのヒープは論理的にグローバルな1つのヒープとプロセッサ毎のヒープに分けられている。さらにスレッド毎のキャッシュを持ち、制限された数のスーパーブロックを保持できる。確保はスレッド毎またはプロセッサ毎のヒープからのみ行い、解放されたスーパーブロックの多くはグローバルなヒープに戻して他のプロセッサが使えるようにする。このようにしてHoardではスレッド数に対してほぼ比例したスケーラビリティを維持しつつ、フラグメンテーションを最小に抑えている。スレッド毎に小さいメモリ確保のための領域を設ける。大きなメモリ確保にはmmapかsbrkを使用する。TCMallocはGoogleが開発したもので、スレッドが終了した際にローカルな領域を掃除するガベージコレクション機能を備えている。マルチスレッド環境では、glibcのptmallocの2倍以上の性能を発揮するという。OSのカーネルでもアプリケーションと同様にメモリ確保が必要である。カーネル内にもcodice_1相当の関数はあるが、その実装はCライブラリのものとは大きく異なる。例えば、DMA用のバッファには特別な制限が課せられることがあるし、割り込み処理でメモリを動的に確保したい場合もある。このため、カーネルの仮想記憶サブシステムと密に連携した codice_1 実装が要求される。codice_1が確保できるメモリブロックの最大サイズはシステムに依存する。特に物理メモリ量とOSの実装に依存する。理論上の最大値はcodice_63型(メモリ領域のサイズを表す符号なし整数)である。その最大値はか、C99標準の定数"SIZE_MAX"である。C言語標準は一回の確保で保証される最小値を提示している(C89では0x7FFF、C99では0xFFFF)。C++でもcodice_1関数は利用できるが、この利用は後述の問題を引き起こすため推奨されない。C++では言語の機能としてnew演算子、delete演算子が用意されている。codice_1で確保したメモリ領域に対してcodice_66したり、逆にcodice_67で確保した領域をcodice_4したりすると結果は未定義となる。codice_1によって生まれたポインタとcodice_67によって生まれたポインタの混在はバグの温床であり、また、new/delete演算子と違い、malloc/free関数ではクラスのコンストラクタとデストラクタが呼ばれないという違いもあり、C++でのcodice_1は禁じ手の扱いである。
出典:wikipedia
LINEスタンプ制作に興味がある場合は、
下記よりスタンプファクトリーのホームページをご覧ください。