メモリ管理—Pythonドキュメント

提供:Dev Guides
< PythonPython/docs/2.7/c-api/memory
移動先:案内検索

メモリ管理

概要

Pythonのメモリ管理には、すべてのPythonオブジェクトとデータ構造を含むプライベートヒープが含まれます。 このプライベートヒープの管理は、 Pythonメモリマネージャーによって内部的に保証されます。 Pythonメモリマネージャーには、共有、セグメンテーション、事前割り当て、キャッシュなど、さまざまな動的ストレージ管理の側面を処理するさまざまなコンポーネントがあります。

最下位レベルでは、rawメモリアロケータは、オペレーティングシステムのメモリマネージャと対話することにより、すべてのPython関連データを格納するための十分なスペースがプライベートヒープにあることを保証します。 生のメモリアロケータに加えて、複数のオブジェクト固有のアロケータが同じヒープ上で動作し、すべてのオブジェクトタイプの特性に適合した個別のメモリ管理ポリシーを実装します。 たとえば、整数は異なるストレージ要件と速度/スペースのトレードオフを意味するため、整数オブジェクトは、文字列、タプル、またはディクショナリとは異なる方法でヒープ内で管理されます。 したがって、Pythonメモリマネージャーは一部の作業をオブジェクト固有のアロケーターに委任しますが、後者がプライベートヒープの範囲内で動作することを保証します。

Pythonヒープの管理はインタプリタ自体によって実行され、そのヒープ内のメモリブロックへのオブジェクトポインタを定期的に操作する場合でも、ユーザーはそれを制御できないことを理解することが重要です。 Pythonオブジェクトおよびその他の内部バッファーへのヒープスペースの割り当ては、このドキュメントに記載されているPython / C API関数を介して、Pythonメモリマネージャーによってオンデマンドで実行されます。

メモリの破損を回避するために、拡張機能の作成者は、Cライブラリによってエクスポートされた関数malloc()calloc()realloc()free()を使用してPythonオブジェクトを操作しようとしないでください。 ]。 これにより、CアロケータとPythonメモリマネージャの間で呼び出しが混在し、致命的な結果が生じます。これらは異なるアルゴリズムを実装し、異なるヒープで動作するためです。 ただし、次の例に示すように、個々の目的のためにCライブラリアロケータを使用してメモリブロックを安全に割り当てたり解放したりできます。

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;

この例では、I / Oバッファのメモリ要求はCライブラリアロケータによって処理されます。 Pythonメモリマネージャは、結果として返される文字列オブジェクトの割り当てにのみ関与します。

ただし、ほとんどの場合、Pythonヒープからメモリを割り当てることをお勧めします。これは、PythonヒープがPythonメモリマネージャーの制御下にあるためです。 たとえば、これは、インタプリタがCで記述された新しいオブジェクトタイプで拡張されている場合に必要です。 Pythonヒープを使用するもう1つの理由は、拡張モジュールのメモリニーズについてPythonメモリマネージャに通知したいという要望です。 要求されたメモリが内部の非常に特殊な目的にのみ使用される場合でも、すべてのメモリ要求をPythonメモリマネージャに委任すると、インタプリタはメモリフットプリント全体のより正確なイメージを得ることができます。 その結果、特定の状況下では、Pythonメモリマネージャーは、ガベージコレクション、メモリ圧縮、その他の予防手順などの適切なアクションをトリガーする場合とトリガーしない場合があります。 前の例で示したようにCライブラリアロケータを使用すると、I / Oバッファに割り当てられたメモリがPythonメモリマネージャから完全にエスケープされることに注意してください。


メモリインターフェース

次の関数セットは、ANSI C標準をモデルにしていますが、ゼロバイトを要求するときの動作を指定しており、Pythonヒープからメモリを割り当てたり解放したりするために使用できます。

void *PyMem_Malloc(size_t n)
n バイトを割り当て、割り当てられたメモリにタイプvoid*のポインタを返します。要求が失敗した場合は、 NULL を返します。 ゼロバイトを要求すると、PyMem_Malloc(1)が代わりに呼び出されたかのように、可能であれば、別個の非 NULL ポインタが返されます。 メモリはいかなる方法でも初期化されていません。
void *PyMem_Realloc(void *p, size_t n)
p が指すメモリブロックのサイズを n バイトに変更します。 内容は、新旧の最小サイズに変更されません。 pNULL の場合、呼び出しはPyMem_Malloc(n)と同等です。 それ以外の場合、 n がゼロに等しい場合、メモリブロックのサイズは変更されますが解放されず、返されるポインタは NULL ではありません。 pNULL でない限り、 PyMem_Malloc()または PyMem_Realloc()への前回の呼び出しによって返されている必要があります。 要求が失敗した場合、 PyMem_Realloc()NULL を返し、 p は前のメモリ領域への有効なポインタのままです。
void PyMem_Free(void *p)
p が指すメモリブロックを解放します。これは、 PyMem_Malloc()または PyMem_Realloc()への前回の呼び出しによって返された必要があります。 それ以外の場合、またはPyMem_Free(p)が以前に呼び出された場合、未定義の動作が発生します。 pNULL の場合、操作は実行されません。

以下のタイプ指向のマクロは、便宜上提供されています。 TYPE は任意のCタイプを指すことに注意してください。

TYPE *PyMem_New(TYPE, size_t n)
PyMem_Malloc()と同じですが、(n * sizeof(TYPE))バイトのメモリを割り当てます。 TYPE*にキャストされたポインタを返します。 メモリはいかなる方法でも初期化されていません。
TYPE *PyMem_Resize(void *p, TYPE, size_t n)
PyMem_Realloc()と同じですが、メモリブロックのサイズが(n * sizeof(TYPE))バイトに変更されます。 TYPE*にキャストされたポインタを返します。 戻ると、 p は新しいメモリ領域へのポインタになり、障害が発生した場合は NULL になります。 これはCプリプロセッサマクロです。 pは常に再割り当てされます。 エラーを処理するときにメモリが失われないように、pの元の値を保存します。
void PyMem_Del(void *p)
PyMem_Free()と同じです。

さらに、上記のC API関数を使用せずに、Pythonメモリアロケータを直接呼び出すために、次のマクロセットが提供されています。 ただし、これらを使用してもPythonバージョン間のバイナリ互換性は維持されないため、拡張モジュールでは非推奨になることに注意してください。

PyMem_MALLOC()PyMem_REALLOC()PyMem_FREE()

PyMem_NEW()PyMem_RESIZE()PyMem_DEL()


オブジェクトアロケータ

次の関数セットは、ANSI C標準をモデルにしていますが、ゼロバイトを要求するときの動作を指定しており、Pythonヒープからメモリを割り当てたり解放したりするために使用できます。

デフォルトでは、これらの関数は pymallocメモリアロケータを使用します。

警告

これらの機能を使用するときは、 GIL を保持する必要があります。


void *PyObject_Malloc(size_t n)

n バイトを割り当て、割り当てられたメモリにタイプvoid*のポインタを返します。要求が失敗した場合は、 NULL を返します。

ゼロバイトを要求すると、PyObject_Malloc(1)が代わりに呼び出されたかのように、可能であれば、別個の非 NULL ポインタが返されます。 メモリはいかなる方法でも初期化されていません。

void *PyObject_Realloc(void *p, size_t n)

p が指すメモリブロックのサイズを n バイトに変更します。 内容は、新旧の最小サイズに変更されません。

pNULL の場合、呼び出しはPyObject_Malloc(n)と同等です。 それ以外の場合、 n がゼロに等しい場合、メモリブロックのサイズは変更されますが解放されず、返されるポインタは NULL ではありません。

pNULL でない限り、 PyObject_Malloc()PyObject_Realloc()、またはPyObject_Calloc()

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

void PyObject_Free(void *p)

p が指すメモリブロックを解放します。これは、 PyObject_Malloc()PyObject_Realloc()、またはPyObject_Calloc()への前回の呼び出しによって返された必要があります。 ]。 それ以外の場合、またはPyObject_Free(p)が以前に呼び出された場合、未定義の動作が発生します。

pNULL の場合、操作は実行されません。

さらに、次のマクロセットが提供されています。


pymallocアロケータ

Pythonには、寿命の短い小さなオブジェクト(512バイト以下)用に最適化された pymalloc アロケータがあります。 256KiBの固定サイズの「アリーナ」と呼ばれるメモリマッピングを使用します。 512バイトを超える割り当ての場合は、malloc()およびrealloc()にフォールバックします。

pymalloc は、 PyObject_Malloc()のデフォルトのアロケータです。

アリーナアロケーターは次の機能を使用します。

  • mmap()およびmunmap()が利用可能な場合、
  • それ以外の場合は、malloc()およびfree()

バージョン2.7.7で変更:しきい値が256バイトから512バイトに変更されました。 アリーナアロケーターは、利用可能な場合、mmap()を使用するようになりました。


これはセクション概要の例で、最初の関数セットを使用してI / OバッファーがPythonヒープから割り当てられるように書き直されています。

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;

タイプ指向の関数セットを使用した同じコード:

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;

上記の2つの例では、バッファーは常に同じセットに属する関数を介して操作されることに注意してください。 実際、特定のメモリブロックに同じメモリAPIファミリを使用する必要があるため、異なるアロケータが混在するリスクが最小限に抑えられます。 次のコードシーケンスには2つのエラーが含まれ、そのうちの1つは、異なるヒープで動作する2つの異なるアロケータが混在しているため、 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_Del()  */

Pythonヒープからのrawメモリブロックの処理を目的とした関数に加えて、Pythonのオブジェクトは、 PyObject_New()PyObject_NewVar()、および PyObject_Del()で割り当ておよび解放されます。

これらについては、Cでの新しいオブジェクトタイプの定義と実装に関する次の章で説明します。