メモリ管理
データの持続性
メモリ管理
PHP Manual

## 基本的なメモリ管理

C 言語でのプログラミングでは、開発者がメモリ管理を自分で行う必要があります。 PHP はウェブサーバのモジュールとして使われることが多いので、 メモリリークを引き起こさないようにメモリ管理が特に重要となります。 さらに注意を要するのは、PHP がスレッド環境で使われる可能性があるということです。 この場合、グローバル変数が競合状態になる可能性があります。 スレッドグローバルなデータの扱いかたについての情報は、 スレッドの分離機能を扱う スレッドセーフなリソースマネージャ のドキュメントを参照ください。

これらに加え、さらに Zend Engine 独特のパターンとして注意しなければならないのは、 比較的短時間の間に zval 構造体やその他の小さなメモリブロックの確保と解放を 頻繁に繰り返すということです。PHP のメモリ管理では、 memory_limit にも注意を払わなければなりません。

これらの要件を満たすために Zend Engine は、 リクエスト単位のデータを処理するための特別なメモリマネージャを提供しています。 リクエスト単位のデータとは、単一のリクエストを処理するためにのみ必要となるデータで リクエストが終了する時点で解放されるものです。 拡張モジュールの作者は、通常は以下の表にあるルーチンを使うだけで済むことになります。 これらは利便性を考慮してマクロとして実装されていますが、 このドキュメントでは関数として扱います。

主要メモリ API 群
プロトタイプ | 説明
--- | ---
`void *emalloc(size_t size)` | `size` バイトのメモリを確保する。
`void *ecalloc(size_t nmemb, size_t size)` | `size` バイトのバッファを `nmemb` 件ぶん作成し、ゼロで初期化する。
`void *erealloc(void *ptr, size_t size)` | バッファ `ptr` のサイズを変更する。 `emalloc` を用いて `size` バイトのメモリを確保する。
`void efree(void *ptr)` | `ptr` が指すバッファを解放する。 解放するバッファは `emalloc` で確保したものでなければならない。
`void *safe_emalloc(size_t nmemb, size_t size, size_t offset)` | `size` バイトのブロックを `nmemb` 個、そしてそれに加えて `offset` バイトを保持するバッファを確保する。 `emalloc(nmemb * size + offset)` と似ているが、 それに加えてオーバーフロー対策の特別なプロテクトが施される。
`char *estrdup(const char *s)` | NULL 終端の文字列 `s` を保持できる大きさのバッファを確保し、 `s` をそのバッファにコピーする。
`char *estrndup(const char *s, unsigned int length)` | `estrdup` と似ているが、NULL 終端文字列の長さが事前にわかっている場合に使う。

> 注意: C 標準ライブラリの同等の関数群とは異なり、Zend Engine のメモリ管理関数はメモリの確保に失敗しても NULL を返しません。 そのかわりに、処理を放棄して現在のリクエストを終了させます。

上でも説明したように、メモリをきちんと管理してメモリリークを防ぐことは非常に大切です。 確保したメモリは、不要になったらすぐ解放するようにしましょう。 安全策として、Zend Engine では、上の API 群で確保したメモリは リクエストの終了時にすべて解放するようになっています。 `--enable-debug` オプションつきで PHP をビルドした場合は、 これは警告を発生させます。

例1 PHP のメモリリーク警告

    ZEND_FUNCTION(leak)
    {
        long leakbytes = 3;

        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &leakbytes) == FAILURE) {
            return;
        }

        emalloc(leakbytes);
    }

上の例の出力は、 たとえば以下のようになります。

    [Thu Oct 22 02:14:57 2009]  Script:  '-'
    /home/johannes/src/PHP_5_3/Zend/zend_builtin_functions.c(1377) :  Freeing 0x088888D4 (3 bytes), script=-
    === Total 1 memory leaks detected ===

> 注意: PHP の変数を扱う際には、変数用のメモリを emalloc で確保して参照カウンタに注意を払う必要があります。 詳細は 変数の作成 を参照ください。

> 注意: このリーク検出機能が働くのは、emalloc で確保したメモリブロックに対してのみです。 より詳細な解析を行うには、valgrind や libumem といったメモリチェッカーを使うことをおすすめします。 これらによる解析時には、PHP のメモリチェッカーを無効化することもできます。 そのためには、環境変数 USE_ZEND_ALLOC=0 を設定してから PHP を開始させます。

メモリ管理
データの持続性
メモリ管理
PHP Manual