\chapter{メモリ管理 \label{memory}}
\sectionauthor{Vladimir Marangozov}{Vladimir.Marangozov@inrialpes.fr}


\section{概要 \label{memoryOverview}}

Python におけるメモリ管理には、全ての Python オブジェクトとデータ構造が
入ったプライベートヒープ (private heap) が必須です。プライベートヒープ
の管理は、内部的には
\emph{Python メモリマネージャ (Python memory manager)}
が確実に行います。Python メモリマネージャには、共有 (sharing)、
セグメント分割 (segmentation)、事前割り当て (preallocation)、
キャッシュ化 (caching) といった、様々な動的記憶管理の側面を
扱うために、個別のコンポーネントがあります。

最低水準層では、素のメモリ操作関数 (raw memory allocator) が
オペレーティングシステムのメモリ管理機構とやりとりして、 
プライベートヒープ内にPython 関連の全てのデータを記憶するのに
十分な空きがあるかどうか確認します。
素のメモリ操作関数の上には、いくつかのオブジェクト固有の
メモリ操作関数があります。これらは同じヒープを操作し、
各オブジェクト型固有の事情に合ったメモリ管理ポリシを実装しています。
例えば、整数オブジェクトは文字列やタプル、辞書とは違ったやり方で
ヒープ内で管理されます。というのも、整数には値を記憶する上で
特別な要件があり、速度/容量のトレードオフが存在するからです。
このように、 Python メモリマネジャは作業のいくつかをオブジェクト
固有のメモリ操作関数に委譲しますが、これらの関数が
プライベートヒープからはみ出してメモリ管理を行わないように
しています。

重要なのは、たとえユーザがいつもヒープ内のメモリブロックを指すような
オブジェクトポインタを操作しているとしても、Python 用ヒープの管理は
インタプリタ自体が行うもので、ユーザがそれを制御する余地はないと理解
することです。Python オブジェクトや内部使用されるバッファを入れるための
ヒープ空間のメモリ確保は、必要に応じて、Python メモリマネージャがこの
ドキュメント内で列挙しているPython/C API 関数群を介して行います。

メモリ管理の崩壊を避けるため、拡張モジュールの作者は決して Python 
オブジェクトを C ライブラリが公開している関数: 
\cfunction{malloc()}\ttindex{malloc()}、
\cfunction{calloc()}\ttindex{calloc()}、
\cfunction{realloc()}\ttindex{realloc()} および
\cfunction{free()}\ttindex{free()} で操作しようとしては
なりません。こうした関数を使うと、C のメモリ操作関数と
Python メモリマネージャとの間で関数呼び出しが交錯します。
C のメモリ操作関数とPython メモリマネージャは異なる
アルゴリズムで実装されていて、異なるヒープを操作するため、
呼び出しの交錯は致命的な結果を招きます。
とはいえ、個別の目的のためなら、 C ライブラリのメモリ操作関数を
使って安全にメモリを確保したり解放したりできます。
例えば、以下がそのような例です:

\begin{verbatim}
    PyObject *res;
    char *buf = (char *) malloc(BUFSIZ); /* for I/O */

    if (buf == NULL)
        return PyErr_NoMemory();
    ...Do some I/O operation involving buf...
    res = PyString_FromString(buf);
    free(buf); /* malloc'ed */
    return res;
\end{verbatim}

この例では、I/O バッファに対するメモリ要求は C ライブラリのメモリ
操作関数を使っています。 Python メモリマネジャは戻り値として
返される文字列オブジェクトを確保する時にだけ必要です。

とはいえ、ほとんどの状況では、メモリの操作は Python ヒープに
固定して行うよう勧めます。なぜなら、Python ヒープは Python 
メモリマネジャの管理下にあるからです。
例えば、インタプリタを C で書かれた新たなオブジェクト型で拡張
する際には、ヒープでのメモリ管理が必要です。
Python ヒープを使った方がよいもう一つの理由として、拡張モジュールが
必要としているメモリについて Python メモリマネージャに
\emph{情報を提供} してほしいということがあります。
たとえ必要なメモリが内部的かつ非常に特化した用途に対して排他的に
用いられるものだとしても、全てのメモリ操作要求を Python メモリマネージャ
に委譲すれば、インタプリタはより正確なメモリフットプリント
(memory footprint) の全体像を把握できます。その結果、特定の状況では、
Python メモリマネージャがガベージコレクションやメモリのコンパクト化、
その他何らかの予防措置といった、適切な動作をトリガできることが
あります。上の例で示したように C ライブラリのメモリ操作関数
を使うと、 I/O バッファ用に確保したメモリは Python メモリマネージャ
の管理から完全に外れることに注意してください。


\section{メモリインタフェース \label{memoryInterface}}

Python ヒープに対してメモリを確保したり解放したりするために、
以下の関数セットが利用できます。これらの関数は ANSI C 標準に
従ってモデル化されていますが、0 バイトの領域を要求した際の
動作についても定義しています:


\begin{cfuncdesc}{void*}{PyMem_Malloc}{size_t n}
\var{n} バイトをメモリ確保し、確保されたメモリを指す \ctype{void*} 
型のポインタを返します。確保要求に失敗した場合には \NULL{} を
返します。
0 バイトをリクエストすると、可能ならば独立した非\NULL{} の
ポインタを返します。このポインタは  \cfunction{PyMem_Malloc(1)} 
を代わりに呼んだときのようなメモリ領域を指しています。
確保されたメモリ領域はいかなる初期化も行われていません。
\end{cfuncdesc}

\begin{cfuncdesc}{void*}{PyMem_Realloc}{void *p, size_t n}
\var{p} が指しているメモリブロックを \var{n} バイトにサイズ変更
します。メモリの内容のうち、新旧のサイズのうち小さい方までの
領域は変更されません。\var{p} が \NULL ならば、この関数は
\cfunction{PyMem_Malloc(\var{n})} と等価になります; 
それ以外の場合で、\var{n} がゼロに等しければ、
メモリブロックはサイズ変更されますが、解放されず、非 \NULL の
ポインタを返します。\var{p} の値を\NULL にしないのなら、
以前呼び出した \cfunction{PyMem_Malloc()} や 
\cfunction{PyMem_Realloc()} の返した値でなければなりません。
\end{cfuncdesc}

\begin{cfuncdesc}{void}{PyMem_Free}{void *p}
\var{p} が指すメモリブロックを解放します。\var{p} は
以前呼び出した \cfunction{PyMem_Malloc()} や 
\cfunction{PyMem_Realloc()} の返した値でなければなりません。
それ以外の場合や、すでに \cfunction{PyMem_Free(p)} を
呼び出した後だった場合、未定義の動作になります。
\var{p} が \NULL なら、何も行いません。
\end{cfuncdesc}

以下に挙げる型対象のマクロは利便性のために提供されているものです。
\var{TYPE} は任意の C の型を表します。

\begin{cfuncdesc}{\var{TYPE}*}{PyMem_New}{TYPE, size_t n}
\cfunction{PyMem_Malloc()} と同じですが、
\code{(\var{n} * sizeof(\var{TYPE}))} バイトのメモリを確保します。
\ctype{\var{TYPE}*} に型キャストされたポインタを返します。
メモリには何の初期化も行われていません。
\end{cfuncdesc}

\begin{cfuncdesc}{\var{TYPE}*}{PyMem_Resize}{void *p, TYPE, size_t n}
\cfunction{PyMem_Realloc()} と同じですが、
\code{(\var{n} * sizeof(\var{TYPE}))} バイトにサイズ変更されたメモリを
確保します。
\ctype{\var{TYPE}*} に型キャストされたポインタを返します。
\end{cfuncdesc}

\begin{cfuncdesc}{void}{PyMem_Del}{void *p}
\cfunction{PyMem_Free()} と同じです。
\end{cfuncdesc}

上記に加えて、C API 関数を介することなく Python メモリ操作関数を
直接呼び出すための以下のマクロセットが提供されています。
ただし、これらのマクロは Python バージョン間でのバイナリ互換性を
保てず、それゆえに拡張モジュールでは撤廃されているので注意してください。

\cfunction{PyMem_MALLOC()}、
\cfunction{PyMem_REALLOC()}、
 \cfunction{PyMem_FREE()}。

\cfunction{PyMem_NEW()}、
\cfunction{PyMem_RESIZE()}、
\cfunction{PyMem_DEL()}。


\section{例 \label{memoryExamples}}

最初に述べた関数セットを使って、\ref{memoryOverview} 節の例を 
Python ヒープに I/O バッファをメモリ確保するように書き換えたものを
以下に示します:

\begin{verbatim}
    PyObject *res;
    char *buf = (char *) PyMem_Malloc(BUFSIZ); /* for I/O */

    if (buf == NULL)
        return PyErr_NoMemory();
    /* ...Do some I/O operation involving buf... */
    res = PyString_FromString(buf);
    PyMem_Free(buf); /* allocated with PyMem_Malloc */
    return res;
\end{verbatim}

同じコードを型対象の関数セットで書いたものを以下に示します:

\begin{verbatim}
    PyObject *res;
    char *buf = PyMem_New(char, BUFSIZ); /* for I/O */

    if (buf == NULL)
        return PyErr_NoMemory();
    /* ...Do some I/O operation involving buf... */
    res = PyString_FromString(buf);
    PyMem_Del(buf); /* allocated with PyMem_New */
    return res;
\end{verbatim}

上の二つの例では、バッファを常に同じ関数セットに属する関数で
操作していることに注意してください。
実際、あるメモリブロックに対する操作は、異なるメモリ操作機構を
混用する危険を減らすために、同じメモリ API ファミリを使って行うことが
必要です。以下のコードには二つのエラーがあり、そのうちの一つには
異なるヒープを操作する別のメモリ操作関数を混用しているので
\emph{致命的 (Fatal)} とラベルづけをしています。

\begin{verbatim}
char *buf1 = PyMem_New(char, BUFSIZ);
char *buf2 = (char *) malloc(BUFSIZ);
char *buf3 = (char *) PyMem_Malloc(BUFSIZ);
...
PyMem_Del(buf3);  /* Wrong -- should be PyMem_Free() */
free(buf2);       /* Right -- allocated via malloc() */
free(buf1);       /* Fatal -- should be PyMem_Del()  */
\end{verbatim}

素のメモリブロックを Python ヒープ上で操作する関数に加え、
\cfunction{PyObject_New()}、 \cfunction{PyObject_NewVar()}、および
\cfunction{PyObject_Del()} を使うと、 Python におけるオブジェクトを
メモリ確保したり解放したりできます。

これらの関数については、次章の C による新しいオブジェクト型の定義や
実装に関する記述の中で説明します。
