メモリ管理
**********


概要
====

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

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

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

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

   PyObject *res;
   char *buf = (char *) malloc(BUFSIZ); /* I/O 用 */

   if (buf == NULL)
       return PyErr_NoMemory();
   ...buf を使って何らかの I/O 操作を行う...
   res = PyBytes_FromString(buf);
   free(buf); /* malloc で割り当て済み */
   return res;

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

In most situations, however, it is recommended to allocate memory from
the Python heap specifically because the latter is under control of
the Python memory manager. For example, this is required when the
interpreter is extended with new object types written in C. Another
reason for using the Python heap is the desire to *inform* the Python
memory manager about the memory needs of the extension module. Even
when the requested memory is used exclusively for internal, highly
specific purposes, delegating all memory requests to the Python memory
manager causes the interpreter to have a more accurate image of its
memory footprint as a whole. Consequently, under certain
circumstances, the Python memory manager may or may not trigger
appropriate actions, like garbage collection, memory compaction or
other preventive procedures. Note that by using the C library
allocator as shown in the previous example, the allocated memory for
the I/O buffer completely escapes the Python memory manager.

参考:

  環境変数 "PYTHONMALLOC" を使用して Python が利用するメモリアロケータ
  を制御することができます。

  環境変数 "PYTHONMALLOCSTATS" を使用して、新たなオブジェクトアリーナ
  が生成される時と、シャットダウン時に pymalloc メモリアロケータ の統
  計情報を表示できます。


アロケータドメイン
==================

すべてのメモリ割り当て関数は、三つの「ドメイン」のいずれかに属します
("PyMemAllocatorDomain" も参照)。 各ドメインは異なる割り当て方針を表し
、異なる用途に最適化されています。 各ドメインがどうメモリを割り当て、
内部でどの関数を呼ぶかは実装の詳細ですが、デバッグ用の簡略化した表を
デフォルトのメモリアロケータ に示します。 あるメモリブロックの割り当て
と解放に使う API は、同じドメインに属している必要があります。 例えば
"PyMem_Malloc()" で割り当てたメモリは "PyMem_Free()" で解放しなければ
なりません。

三つの割り当てドメインは次のとおりです。

* Raw ドメイン: システムアロケータによる割り当てが *必要* な場合や、*
  アタッチされたスレッド状態* なしで動作できるアロケータが必要な場合に
  、汎用メモリバッファを割り当てるためのものです。 メモリはシステムに
  直接要求します。 生メモリインターフェース を参照してください。

* Mem ドメイン: *スレッド状態がアタッチされた* 状態で、Python のバッフ
  ァや汎用メモリバッファを割り当てるためのものです。 メモリは Python
  のプライベートヒープから取得します。 メモリインターフェース を参照し
  てください。

* Object ドメイン: Python オブジェクト用のメモリを割り当てるためのもの
  です。 メモリは Python のプライベートヒープから取得します。 オブジェ
  クトアロケータ を参照してください。

注釈:

  *フリースレッド* ビルドでは、object ドメインで割り当てるのは Python
  オブジェクトだけとし、すべての Python オブジェクトをそのドメインで割
  り当てる必要があります。 以前の Python では推奨事項にすぎませんでし
  たが、フリースレッドビルドでは必須の要件です。例えば、Python オブジ
  ェクトではないバッファは "PyObject_Malloc()" ではなく、
  "PyMem_Malloc()"、"PyMem_RawMalloc()"、"malloc()" で割り当ててくださ
  い。メモリ割り当て API を参照してください。


生メモリインターフェース
========================

以下の関数群は、システムアロケータのラッパーです。 これらはスレッドセ
ーフなので、*スレッド状態* が *アタッチされている* 必要はありません。

デフォルトの生メモリアロケータ は "malloc()"、"calloc()"、"realloc()"
、"free()" を使います。 0 バイトの要求には "malloc(1)" または
"calloc(1, 1)" を呼び出します。

Added in version 3.4.

void *PyMem_RawMalloc(size_t n)
    * 次に属します: Stable ABI (バージョン 3.13 より).*

   *n* バイトを割り当て、そのメモリを指す void* 型のポインタを返します
   。要求が失敗した場合 "NULL" を返します。

   0バイトを要求すると、 "PyMem_RawMalloc(1)" が呼ばれたときと同じよう
   に、可能なら "NULL" でないユニークなポインタを返します。確保された
   メモリーにはいかなる初期化も行われません。

void *PyMem_RawCalloc(size_t nelem, size_t elsize)
    * 次に属します: Stable ABI (バージョン 3.13 より).*

   サイズ "elsize" バイトの要素 "nelem" 個分のメモリを割り当て、その領
   域への void* ポインタを返します。 要求が失敗した場合は "NULL" を返
   します。 メモリはゼロで初期化されます。

   要素数か要素のサイズが0バイトの要求に対しては、可能なら
   "PyMem_RawCalloc(1, 1)" が呼ばれたのと同じように、ユニークな "NULL"
   でないポインタを返します。

   Added in version 3.5.

void *PyMem_RawRealloc(void *p, size_t n)
    * 次に属します: Stable ABI (バージョン 3.13 より).*

   *p* が指すメモリブロックを *n* バイトにリサイズします。古いサイズと
   新しいサイズの小さい方までの内容は変更されません。

   *p* が "NULL" の場合呼び出しは "PyMem_RawMalloc(n)" と等価です。そ
   うでなく、 *n* がゼロに等しい場合、メモリブロックはリサイズされます
   が解放されません。返されたポインタは非 "NULL" です。

   *p* が "NULL" でない限り、*p* はそれより前の "PyMem_RawMalloc()",
   "PyMem_RawRealloc()", "PyMem_RawCalloc()" の呼び出しにより返されな
   ければなりません。

   要求が失敗した場合 "PyMem_RawRealloc()" は "NULL" を返し、 *p* は前
   のメモリエリアをさす有効なポインタのままです。

void PyMem_RawFree(void *p)
    * 次に属します: Stable ABI (バージョン 3.13 より).*

   *p* が指すメモリブロックを解放します。 *p* は以前呼び出した
   "PyMem_RawMalloc()", "PyMem_RawRealloc()",  "PyMem_RawCalloc()" の
   返した値でなければなりません。それ以外の場合や "PyMem_RawFree(p)"
   を呼び出した後だった場合、未定義の動作になります。

   *p* が "NULL" の場合何もしません。


メモリインターフェース
======================

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

GIL が有効なビルド (デフォルトのビルド) では、デフォルトのメモリアロケ
ータ は pymalloc メモリアロケータ を使います。 *フリースレッドビルド*
では、代わりに mimalloc メモリアロケータ がデフォルトです。

警告:

  これらの関数を使うときは *スレッド状態がアタッチされている* 必要があ
  ります。

バージョン 3.6 で変更: デフォルトのアロケータがシステムの "malloc()"
から pymalloc になりました。

バージョン 3.13 で変更: *フリースレッド* ビルドでは、デフォルトのアロ
ケータが mimalloc になりました。

void *PyMem_Malloc(size_t n)
    * 次に属します: Stable ABI.*

   *n* バイトを割り当て、そのメモリを指す void* 型のポインタを返します
   。要求が失敗した場合 "NULL" を返します。

   0バイトを要求すると、 "PyMem_Malloc(1)" が呼ばれたときと同じように
   、可能なら "NULL" でないユニークなポインタを返します。 確保されたメ
   モリーにはいかなる初期化も行われません。

void *PyMem_Calloc(size_t nelem, size_t elsize)
    * 次に属します: Stable ABI (バージョン 3.7 より).*

   サイズ "elsize" バイトの要素 "nelem" 個分のメモリを割り当て、その領
   域への void* ポインタを返します。 要求が失敗した場合は "NULL" を返
   します。 メモリはゼロで初期化されます。

   要素数か要素のサイズが0バイトの要求に対しては、可能なら
   "PyMem_Calloc(1, 1)" が呼ばれたのと同じように、ユニークな "NULL" で
   ないポインタを返します。

   Added in version 3.5.

void *PyMem_Realloc(void *p, size_t n)
    * 次に属します: Stable ABI.*

   *p* が指すメモリブロックを *n* バイトにリサイズします。古いサイズと
   新しいサイズの小さい方までの内容は変更されません。

   *p* が "NULL" の場合呼び出しは "PyMem_Malloc(n)" と等価です。そうで
   なく、 *n* がゼロに等しい場合、メモリブロックはリサイズされますが解
   放されません。返されたポインタは非 "NULL" です。

   *p* が "NULL" でない限り、*p* はそれより前の "PyMem_Malloc()",
   "PyMem_Realloc()" または "PyMem_Calloc()" の呼び出しにより返されな
   ければなりません。

   要求が失敗した場合 "PyMem_Realloc()" は "NULL" を返し、 *p* は前の
   メモリエリアをさす有効なポインタのままです。

void PyMem_Free(void *p)
    * 次に属します: Stable ABI.*

   *p* が指すメモリブロックを解放します。 *p* は以前呼び出した
   "PyMem_Malloc()"、 "PyMem_Realloc()"、または "PyMem_Calloc()" の返
   した値でなければなりません。それ以外の場合や "PyMem_Free(p)" を呼び
   出した後だった場合、未定義の動作になります。

   *p* が "NULL" の場合何もしません。

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

PyMem_New(TYPE, n)

   "PyMem_Malloc()" と同じですが、"(n * sizeof(TYPE))" バイトのメモリ
   を割り当て、"TYPE*" にキャストしたポインタを返します。 メモリはいか
   なる方法でも初期化されません。

PyMem_Resize(p, TYPE, n)

   "PyMem_Realloc()" と同じですが、メモリブロックを "(n *
   sizeof(TYPE))" バイトにリサイズし、"TYPE*" にキャストしたポインタを
   返します。 戻ったときの "p" は、新しいメモリ領域へのポインタ、また
   は失敗した場合は "NULL" です。

   これは C プリプロセッサマクロです。*p* は常に再代入されます。エラー
   処理時にメモリを失うのを避けるには *p* の元の値を保存してください。

void PyMem_Del(void *p)

   "PyMem_Free()" と同じです。


非推奨のエイリアス
------------------

これらは既存の関数やマクロの *緩やかに非推奨* な別名です。 後方互換性
のためだけに存在します。

+----------------------------------------------------+----------------------------------------------------+
| 非推奨のエイリアス                                 | 対応する関数またはマクロ                           |
|====================================================|====================================================|
| PyMem_MALLOC(size)                                 | "PyMem_Malloc()"                                   |
+----------------------------------------------------+----------------------------------------------------+
| PyMem_NEW(type, size)                              | "PyMem_New"                                        |
+----------------------------------------------------+----------------------------------------------------+
| PyMem_REALLOC(ptr, size)                           | "PyMem_Realloc()"                                  |
+----------------------------------------------------+----------------------------------------------------+
| PyMem_RESIZE(ptr, type, size)                      | "PyMem_Resize"                                     |
+----------------------------------------------------+----------------------------------------------------+
| PyMem_FREE(ptr)                                    | "PyMem_Free()"                                     |
+----------------------------------------------------+----------------------------------------------------+
| PyMem_DEL(ptr)                                     | "PyMem_Free()"                                     |
+----------------------------------------------------+----------------------------------------------------+

バージョン 3.4 で変更: これらのマクロは、対応する関数やマクロの別名に
なりました。 以前も動作は同じでしたが、使うと Python バージョン間のバ
イナリ互換性が保たれるとは限りませんでした。

バージョン 2.0 で非推奨.


オブジェクトアロケータ
======================

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

注釈:

  メモリアロケータのカスタマイズ で説明する方法でこのドメインの割り当
  て関数を差し替えて処理を挟む場合、返されるメモリを Python オブジェク
  トへ安全にキャストできる保証はありません。

デフォルトのオブジェクトアロケータ は pymalloc メモリアロケータ を使い
ます。 *フリースレッド* ビルドでは、代わりに mimalloc メモリアロケータ
がデフォルトです。

警告:

  これらの関数を使うときは *スレッド状態がアタッチされている* 必要があ
  ります。

void *PyObject_Malloc(size_t n)
    * 次に属します: Stable ABI.*

   *n* バイトを割り当て、そのメモリを指す void* 型のポインタを返します
   。要求が失敗した場合 "NULL" を返します。

   0バイトを要求すると、 "PyObject_Malloc(1)" が呼ばれたときと同じよう
   に、可能なら "NULL" でないユニークなポインタを返します。 確保された
   メモリーにはいかなる初期化も行われません。

void *PyObject_Calloc(size_t nelem, size_t elsize)
    * 次に属します: Stable ABI (バージョン 3.7 より).*

   サイズ "elsize" バイトの要素 "nelem" 個分のメモリを割り当て、その領
   域への void* ポインタを返します。 要求が失敗した場合は "NULL" を返
   します。 メモリはゼロで初期化されます。

   要素数か要素のサイズが0バイトの要求に対しては、可能なら
   "PyObject_Calloc(1, 1)" が呼ばれたのと同じように、ユニークな "NULL"
   でないポインタを返します。

   Added in version 3.5.

void *PyObject_Realloc(void *p, size_t n)
    * 次に属します: Stable ABI.*

   *p* が指すメモリブロックを *n* バイトにリサイズします。古いサイズと
   新しいサイズの小さい方までの内容は変更されません。

   *p* が "NULL" の場合呼び出しは "PyObject_Malloc(n)" と等価です。そ
   うでなく、 *n* がゼロに等しい場合、メモリブロックはリサイズされます
   が解放されません。返されたポインタは非 "NULL" です。

   *p* が "NULL" でない限り、*p* はそれより前の "PyObject_Malloc()",
   "PyObject_Realloc()" または "PyObject_Calloc()" の呼び出しにより返
   されなければなりません。

   要求が失敗した場合 "PyObject_Realloc()" は "NULL" を返し、 *p* は前
   のメモリエリアをさす有効なポインタのままです。

void PyObject_Free(void *p)
    * 次に属します: Stable ABI.*

   *p* が指すメモリブロックを解放します。 *p* は以前呼び出した
   "PyObject_Malloc()"、 "PyObject_Realloc()"、または
   "PyObject_Calloc()" の返した値でなければなりません。それ以外の場合
   や "PyObject_Free(p)" を呼び出した後だった場合、未定義の動作になり
   ます。

   *p* が "NULL" の場合何もしません。

   オブジェクトのメモリを解放するために直接呼び出さず、代わりに型の
   "tp_free" スロットを呼び出してください。

   "PyObject_GC_New" または "PyObject_GC_NewVar" で割り当てたメモリに
   は使わないでください。 代わりに "PyObject_GC_Del()" を使ってくださ
   い。

   参考:

     * ガベージコレクションをサポートする型が割り当てたメモリに対して
       は、"PyObject_GC_Del()" がこの関数に相当します。

     * "PyObject_Malloc()"

     * "PyObject_Realloc()"

     * "PyObject_Calloc()"

     * "PyObject_New"

     * "PyObject_NewVar"

     * "PyType_GenericAlloc()"

     * "tp_free"


デフォルトのメモリアロケータ
============================

デフォルトのメモリアロケータは次のとおりです。

+-------------------------------------+-------------------------+----------------------+------------------------+------------------------+
| 構成                                | 名前                    | PyMem_RawMalloc      | PyMem_Malloc           | PyObject_Malloc        |
|=====================================|=========================|======================|========================|========================|
| リリースビルド                      | ""pymalloc""            | "malloc"             | "pymalloc"             | "pymalloc"             |
+-------------------------------------+-------------------------+----------------------+------------------------+------------------------+
| デバッグビルド                      | ""pymalloc_debug""      | "malloc" + debug     | "pymalloc" + debug     | "pymalloc" + debug     |
+-------------------------------------+-------------------------+----------------------+------------------------+------------------------+
| pymalloc 無しのリリースビルド       | ""malloc""              | "malloc"             | "malloc"               | "malloc"               |
+-------------------------------------+-------------------------+----------------------+------------------------+------------------------+
| pymalloc 無しのデバッグビルド       | ""malloc_debug""        | "malloc" + debug     | "malloc" + debug       | "malloc" + debug       |
+-------------------------------------+-------------------------+----------------------+------------------------+------------------------+
| フリースレッドビルド                | ""mimalloc""            | "mimalloc"           | "mimalloc"             | "mimalloc"             |
+-------------------------------------+-------------------------+----------------------+------------------------+------------------------+
| フリースレッドのデバッグビルド      | ""mimalloc_debug""      | "mimalloc" + debug   | "mimalloc" + debug     | "mimalloc" + debug     |
+-------------------------------------+-------------------------+----------------------+------------------------+------------------------+

説明:

* 名前: 環境変数 "PYTHONMALLOC" に指定する値。

* "malloc": 標準 C ライブラリのシステムアロケータ。 C 関数 "malloc()"
  、"calloc()"、"realloc()"、"free()" です。

* "pymalloc": pymalloc メモリアロケータ。

* "mimalloc": mimalloc メモリアロケータ。

* "+ debug": Python メモリアロケータのデバッグフック 付き。

* 「デバッグビルド」: デバッグモードでの Python ビルド。


メモリアロケータをカスタマイズする
==================================

Added in version 3.4.

type PyMemAllocatorEx

   メモリブロックのアロケータを記述する構造体です。 以下のフィールドを
   持ちます。

   +------------------------------------------------------------+-----------------------------------------+
   | フィールド                                                 | 意味                                    |
   |============================================================|=========================================|
   | "void *ctx"                                                | 第一引数として渡されるユーザコンテキス  |
   |                                                            | ト                                      |
   +------------------------------------------------------------+-----------------------------------------+
   | "void* malloc(void *ctx, size_t size)"                     | メモリブロックを割り当てます            |
   +------------------------------------------------------------+-----------------------------------------+
   | "void* calloc(void *ctx, size_t nelem, size_t elsize)"     | 0で初期化されたメモリブロックを割り当て |
   |                                                            | ます                                    |
   +------------------------------------------------------------+-----------------------------------------+
   | "void* realloc(void *ctx, void *ptr, size_t new_size)"     | メモリブロックを割り当てるかリサイズし  |
   |                                                            | ます                                    |
   +------------------------------------------------------------+-----------------------------------------+
   | "void free(void *ctx, void *ptr)"                          | メモリブロックを解放する                |
   +------------------------------------------------------------+-----------------------------------------+

   バージョン 3.5 で変更: "PyMemAllocator" 構造体を "PyMemAllocatorEx"
   に改名し、新しい "calloc" フィールドを追加しました。

type PyMemAllocatorDomain

   アロケータドメインを同定するための列挙型です。ドメインは:

   PYMEM_DOMAIN_RAW

      関数:

      * "PyMem_RawMalloc()"

      * "PyMem_RawRealloc()"

      * "PyMem_RawCalloc()"

      * "PyMem_RawFree()"

   PYMEM_DOMAIN_MEM

      関数:

      * "PyMem_Malloc()",

      * "PyMem_Realloc()"

      * "PyMem_Calloc()"

      * "PyMem_Free()"

   PYMEM_DOMAIN_OBJ

      関数:

      * "PyObject_Malloc()"

      * "PyObject_Realloc()"

      * "PyObject_Calloc()"

      * "PyObject_Free()"

void PyMem_GetAllocator(PyMemAllocatorDomain domain, PyMemAllocatorEx *allocator)

   指定されたドメインのメモリブロックアロケータを取得します。

void PyMem_SetAllocator(PyMemAllocatorDomain domain, PyMemAllocatorEx *allocator)

   指定されたドメインのメモリブロックアロケータを設定します。

   新しいアロケータは、0バイトを要求されたときユニークな "NULL" でない
   ポインタを返さなければなりません。

   "PYMEM_DOMAIN_RAW" ドメインでは、*スレッド状態* が *アタッチされて
   いない* 状態で呼び出されるため、アロケータはスレッドセーフでなけれ
   ばなりません。

   ほかのドメインでも、*GIL* を共有しない異なるインタープリタから呼び
   出される場合があるため、アロケータはスレッドセーフでなければなりま
   せん。

   新しいアロケータがフックでない (1つ前のアロケータを呼び出さない) 場
   合、 "PyMem_SetupDebugHooks()" 関数を呼び出して、新しいアロケータの
   上にデバッグフックを再度設置しなければなりません。

   "PyPreConfig.allocator" と PyPreConfig による Python の事前初期化
   も参照してください。

   警告:

     "PyMem_SetAllocator()" には次の規約があります。

     * "Py_PreInitialize()" の後、"Py_InitializeFromConfig()" の前に呼
       び出すと、カスタムのメモリアロケータを設定できます。 設定するア
       ロケータに対しては、ドメインの要件以外の制約はありません。 例え
       ば Raw ドメインでは、*アタッチされたスレッド状態* がなくてもア
       ロケータを呼び出せます。 詳細は アロケータドメインの節 を参照し
       てください。

     * Python の初期化完了後 ("Py_InitializeFromConfig()" の呼び出し後
       ) に呼び出す場合、アロケータは既存のアロケータを **必ず** ラッ
       プしなければなりません。 現在のアロケータを別の任意のアロケータ
       で置き換えることは **サポートされていません**。

   バージョン 3.12 で変更: すべてのアロケータがスレッドセーフである必
   要があります。

void PyMem_SetupDebugHooks(void)

   メモリエラーを検出するために Python メモリアロケータのデバッグフッ
   ク を設定します。


Python メモリアロケータのデバッグフック
=======================================

デバッグモードで Python をビルドした 場合、Python の事前初期化 で
"PyMem_SetupDebugHooks()" を呼び出し、メモリエラーを検出するデバッグフ
ックをメモリアロケータに設定します。

リリースモードでコンパイルした Python でも、環境変数 "PYTHONMALLOC" で
デバッグフックを設定できます (例: "PYTHONMALLOC=debug")。

"PyMem_SetAllocator()" を呼び出した後で、"PyMem_SetupDebugHooks()" に
よってデバッグフックを設定できます。

これらのデバッグフックは、動的に割り当てられたメモリブロックを識別しや
すい特別なビットパターンで埋めます。 新しく割り当てたメモリはバイト
"0xCD" ("PYMEM_CLEANBYTE")、解放したメモリはバイト "0xDD"
("PYMEM_DEADBYTE") で埋めます。 メモリブロックの前後には、バイト
"0xFD" ("PYMEM_FORBIDDENBYTE") で埋めた「禁止バイト」を置きます。 これ
らのバイトの並びは、有効なアドレス、浮動小数点数、ASCII 文字列にはなり
にくいものです。

実行時チェック:

* API の誤用を検出します。 例えば、"PyMem_Malloc()" で割り当てたメモリ
  ブロックに "PyObject_Free()" を呼び出した場合を検出します。

* バッファの先頭より前への書き込み (バッファアンダーフロー) を検出しま
  す。

* バッファの末尾より後への書き込み (バッファオーバーフロー) を検出しま
  す。

* "PYMEM_DOMAIN_OBJ" (例: "PyObject_Malloc()") と "PYMEM_DOMAIN_MEM" (
  例: "PyMem_Malloc()") のアロケータ関数を呼び出すときに、*スレッド状
  態がアタッチされている* ことを確認します。

エラーの場合、デバッグフックは "tracemalloc" を使って、メモリブロック
を割り当てた箇所のトレースバックを取得します。 表示されるのは、
"tracemalloc" が Python のメモリ割り当てを追跡しており、そのブロックが
追跡対象だった場合だけです。

Let *S* = "sizeof(size_t)". "2*S" bytes are added at each end of each
block of *N* bytes requested.  The memory layout is like so, where p
represents the address returned by a malloc-like or realloc-like
function ("p[i:j]" means the slice of bytes from "*(p+i)" inclusive up
to "*(p+j)" exclusive; note that the treatment of negative indices
differs from a Python slice):

"p[-2*S:-S]"
   元の要求バイト数です。 メモリダンプで読みやすいように、ビッグエンデ
   ィアンの size_t で格納します。

"p[-S]"
   API 識別子 (ASCII 文字)。

   * "PYMEM_DOMAIN_RAW" は "'r'"。

   * "PYMEM_DOMAIN_MEM" は "'m'"。

   * "PYMEM_DOMAIN_OBJ" は "'o'"。

"p[-S+1:0]"
   PYMEM_FORBIDDENBYTE の繰り返しです。 領域の手前への書き込みや読み取
   りを検出するために使います。

"p[0:N]"
   要求されたメモリ領域は、未初期化メモリへのアクセスを検出するために
   PYMEM_CLEANBYTE で埋めます。 realloc 系の関数で領域を拡大した場合、
   追加部分も PYMEM_CLEANBYTE で埋めます。 free 系の関数を呼び出すと、
   解放済みメモリへのアクセスを検出するために PYMEM_DEADBYTE で上書き
   します。 realloc 系の関数で領域を縮小した場合も、不要になった元の領
   域を PYMEM_DEADBYTE で埋めます。

"p[N:N+S]"
   PYMEM_FORBIDDENBYTE の繰り返しです。 領域の後ろへの書き込みや読み取
   りを検出するために使います。

"p[N+S:N+2*S]"
   "PYMEM_DEBUG_SERIALNO" マクロが定義されている場合だけ使います (デフ
   ォルトでは未定義)。

   malloc 系または realloc 系の関数の呼び出しごとに 1 増える通し番号で
   す。 ビッグエンディアンの "size_t" で格納します。 後で「不正なメモ
   リ」を検出した場合、この番号を使って次回の実行でブレークポイントを
   設定すると、そのブロックを渡した瞬間を捉えられます。 obmalloc.c の
   静的関数 bumpserialno() だけがこの番号を増やし、そのようなブレーク
   ポイントを簡単に設定できるようになっています。

realloc 系や free 系の関数は、まず領域の前後の PYMEM_FORBIDDENBYTE が
変わっていないことを確認します。 変更されていれば stderr に診断情報を
出力し、Py_FatalError() でプログラムを中止します。 もう一つの主な失敗
の形は、プログラムが特別なビットパターンを読み取り、アドレスとして使お
うとしてメモリエラーになることです。 その時点でデバッガからオブジェク
トを調べると、全体が PYMEM_DEADBYTE (解放済みメモリを使用) または
PYMEM_CLEANBYTE (未初期化メモリを使用) で埋まっている可能性が高いです
。

バージョン 3.6 で変更: "PyMem_SetupDebugHooks()" はリリースモードでコ
ンパイルした Python でも動作するようになりました。 エラーの場合、デバ
ッグフックは "tracemalloc" を使って割り当て箇所のトレースバックを取得
するようになりました。 また、"PYMEM_DOMAIN_OBJ" と "PYMEM_DOMAIN_MEM"
の関数を呼び出すときに、*スレッド状態がアタッチされている* ことも確認
するようになりました。

バージョン 3.8 で変更: Windows CRT のデバッグ版 "malloc()" と "free()"
と同じ値を使うため、バイトパターン "0xCB" ("PYMEM_CLEANBYTE")、"0xDB"
("PYMEM_DEADBYTE")、"0xFB" ("PYMEM_FORBIDDENBYTE") を、それぞれ "0xCD"
、"0xDD"、"0xFD" に変更しました。


pymalloc アロケータ
===================

Python には、寿命の短い小さなオブジェクト (512 バイト以下) に最適化さ
れた *pymalloc* アロケータがあります。 「アリーナ」と呼ぶメモリマッピ
ングを使い、その固定サイズは 32 ビットのプラットフォームでは 256 KiB、
64 ビットでは 1 MiB です。 "--with-pymalloc-hugepages" で Python を構
成すると、64 ビットでのアリーナサイズはヒュージページに合わせて 2 MiB
に増えます。 アリーナの割り当てにはヒュージページ (Linux では
"MAP_HUGETLB"、Windows では "MEM_LARGE_PAGES") の使用を試み、使えなけ
れば自動的に通常のページに切り替えます。 512 バイトを超える割り当てに
は "PyMem_RawMalloc()" と "PyMem_RawRealloc()" を使います。

*pymalloc* is the default allocator of the "PYMEM_DOMAIN_MEM" (ex:
"PyMem_Malloc()") and "PYMEM_DOMAIN_OBJ" (ex: "PyObject_Malloc()")
domains.

アリーナアロケータは、次の関数を使います:

* Windows では "VirtualAlloc()" と "VirtualFree()"。

* 利用可能なら "mmap()" と "munmap()"。

* それ以外の場合は "malloc()" と "free()"。

"--without-pymalloc" オプションで Python を構成した場合、このアロケー
タは無効になります。 環境変数 "PYTHONMALLOC" で実行時に無効にすること
もできます (例: "PYTHONMALLOC=malloc")。

C コード内の低レベルのバグ検出に役立つ AddressSanitizer ("--with-
address-sanitizer") を使って Python をビルドする場合、通常は pymalloc
アロケータを無効にするのが適切です。


pymalloc アリーナアロケータのカスタマイズ
-----------------------------------------

Added in version 3.4.

type PyObjectArenaAllocator

   アリーナアロケータを記述するための構造体です。3つのフィールドを持ち
   ます:

   +----------------------------------------------------+-----------------------------------------+
   | フィールド                                         | 意味                                    |
   |====================================================|=========================================|
   | "void *ctx"                                        | 第一引数として渡されるユーザコンテキス  |
   |                                                    | ト                                      |
   +----------------------------------------------------+-----------------------------------------+
   | "void* alloc(void *ctx, size_t size)"              | size バイトのアリーナを割り当てます     |
   +----------------------------------------------------+-----------------------------------------+
   | "void free(void *ctx, void *ptr, size_t size)"     | アリーナを解放します                    |
   +----------------------------------------------------+-----------------------------------------+

void PyObject_GetArenaAllocator(PyObjectArenaAllocator *allocator)

   アリーナアロケータを取得します。

void PyObject_SetArenaAllocator(PyObjectArenaAllocator *allocator)

   アリーナアロケータを設定します。


mimalloc アロケータ
===================

Added in version 3.13.

Python は、基盤となるプラットフォームが対応していれば mimalloc アロケ
ータをサポートします。 mimalloc は優れた性能特性を持つ汎用アロケータで
、当初は Daan Leijen が Koka 言語と Lean 言語のランタイムシステム向け
に開発しました。

小さなオブジェクト (512 バイト以下) に最適化された pymalloc と異なり、
mimalloc は任意のサイズの割り当てを扱います。

*フリースレッド* ビルドでは、mimalloc は "PYMEM_DOMAIN_MEM" と
"PYMEM_DOMAIN_OBJ" ドメインのデフォルトかつ **必須** のアロケータです
。 フリースレッドビルドでは無効にできません。 スレッドごとの mimalloc
ヒープを使うため、ほとんどの場合にロックなしで割り当てと解放を行えます
。

デフォルトの (フリースレッドでない) ビルドでも mimalloc は利用できます
が、デフォルトのアロケータではありません。 実行時に
"PYTHONMALLOC""=mimalloc" で選択できます (デバッグフック を含める場合
は "mimalloc_debug")。 ビルド時には configure オプション "--without-
mimalloc" で無効にできますが、このオプションは "--disable-gil" と併用
できません。


tracemalloc C API
=================

Added in version 3.7.

int PyTraceMalloc_Track(unsigned int domain, uintptr_t ptr, size_t size)

   割り当てられたメモリブロックを "tracemalloc" モジュールで追跡します
   。

   成功した場合は "0" を返し、エラーの場合 (トレースを格納するメモリを
   割り当てられなかった場合) は "-1" を返します。 tracemalloc が無効な
   ら "-2" を返します。

   そのメモリブロックがすでに追跡されていれば、既存のトレースを更新し
   ます。

int PyTraceMalloc_Untrack(unsigned int domain, uintptr_t ptr)

   割り当てられたメモリブロックを "tracemalloc" モジュールの追跡対象か
   ら外します。 追跡されていなければ何もしません。

   tracemalloc が無効なら "-2"、それ以外の場合は "0" を返します。


使用例
======

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

   PyObject *res;
   char *buf = (char *) PyMem_Malloc(BUFSIZ); /* I/O 用 */

   if (buf == NULL)
       return PyErr_NoMemory();
   /* ...buf を使って何らかの I/O 操作を行う... */
   res = PyBytes_FromString(buf);
   PyMem_Free(buf); /* PyMem_Malloc で割り当て済み */
   return res;

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

   PyObject *res;
   char *buf = PyMem_New(char, BUFSIZ); /* I/O 用 */

   if (buf == NULL)
       return PyErr_NoMemory();
   /* ...buf を使って何らかの I/O 操作を行う... */
   res = PyBytes_FromString(buf);
   PyMem_Free(buf); /* PyMem_New で割り当て済み */
   return res;

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

   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_Free()  */

Python ヒープの生メモリブロックを扱う関数に加えて、Python オブジェクト
の割り当てと解放には "PyObject_New"、"PyObject_NewVar"、
"PyObject_Free()" を使います。

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