インターナルPython ー 文字列オブジェクトの生成

前回の続き
インターナルPython ー Pythonの文字列とPyUnicodeObject構造体 - NO!と言えるようになりたい

今回は文字列オブジェクト生成と,バッファの確保についてみてみる.

_PyUnicode_New()関数

文字列を格納するためのバッファを実際に確保するのが,_PyUnicode_New()関数となる.この関数では,PyUnicodeObjectと,文字列を確保するためのバッファを確保し,生成したPyUnicodeObject構造体インスタンスの中身の初期化を行う.

_PyUnicode_New()関数の定義は以下のようになる.なお,引数のlengthはバイト数ではなく,文字列長となる.

/* Objects/unicodeobject.c */
 308 static
 309 PyUnicodeObject *_PyUnicode_New(Py_ssize_t length)
 310 {
 311     register PyUnicodeObject *unicode;
 312 
 313     /* Optimization for empty strings */
 314     if (length == 0 && unicode_empty != NULL) {
 315         Py_INCREF(unicode_empty);
 316         return unicode_empty;
 317     }
 318 
 319     /* Ensure we won't overflow the size. */
 320     if (length > ((PY_SSIZE_T_MAX / sizeof(Py_UNICODE)) - 1)) {
 321         return (PyUnicodeObject *)PyErr_NoMemory();
 322     }
 323 
 324     /* Unicode freelist & memory allocation */
 325     if (free_list) {
 326         unicode = free_list;
 327         free_list = *(PyUnicodeObject **)unicode;
 328         numfree--;
 329         if (unicode->str) {
 330             /* Keep-Alive optimization: we only upsize the buffer,
 331                never downsize it. */
 332             if ((unicode->length < length) &&
 333                 unicode_resize(unicode, length) < 0) {
 334                 PyObject_DEL(unicode->str);
 335                 unicode->str = NULL;
 336             }
 337         }
 338         else {
 339             size_t new_size = sizeof(Py_UNICODE) * ((size_t)length + 1);
 340             unicode->str = (Py_UNICODE*) PyObject_MALLOC(new_size);
 341         }
 342         PyObject_INIT(unicode, &PyUnicode_Type);
 343     }
 344     else {
 345         size_t new_size;
 346         unicode = PyObject_New(PyUnicodeObject, &PyUnicode_Type);
 347         if (unicode == NULL)
 348             return NULL;
 349         new_size = sizeof(Py_UNICODE) * ((size_t)length + 1);
 350         unicode->str = (Py_UNICODE*) PyObject_MALLOC(new_size);
 351     }
 352 
 353     if (!unicode->str) {
 354         PyErr_NoMemory();
 355         goto onError;
 356     }
 357     /* Initialize the first element to guard against cases where
 358      * the caller fails before initializing str -- unicode_resize()
 359      * reads str[0], and the Keep-Alive optimization can keep memory
 360      * allocated for str alive across a call to unicode_dealloc(unicode).
 361      * We don't want unicode_resize to read uninitialized memory in
 362      * that case.
 363      */
 364     unicode->str[0] = 0;
 365     unicode->str[length] = 0;
 366     unicode->length = length;
 367     unicode->hash = -1;
 368     unicode->state = 0;
 369     unicode->defenc = NULL;
 370     return unicode;
 371 
 372   onError:
 373     /* XXX UNREF/NEWREF interface should be more symmetrical */
 374     _Py_DEC_REFTOTAL;
 375     _Py_ForgetReference((PyObject *)unicode);
 376     PyObject_Del(unicode);
 377     return NULL;
 378 }

から文字の扱い

前回,から文字の場合は複数のインスタンスは生成されず,一つだけ生成され,それが再利用されると説明した.314行目のif文内が,から文字扱いとなっている.まず,長さが0であるかを検査され,0でかつ,unicode_emptyがNULLでなければ,unicode_emptyのリファレンスカウントをインクリメントし,それを返り値とする.unicode_emptyは,から文字を表す文字列オブジェクトを保存するグローバル変数となる.

文字列長のチェック

320行目からのif文では,文字列長が最大値を超えないかどうかをチェックしている.PY_SSIZE_T_MAXと,Py_UNICODEの定義は以下のようになる.

/* Include/pyport.h */
 178 #define PY_SSIZE_T_MAX ((Py_ssize_t)(((size_t)-1)>>1))
 129 /* Py_UNICODE is the native Unicode storage format (code unit) used by
 130    Python and represents a single Unicode element in the Unicode
 131    type. */
 132 
 133 typedef PY_UNICODE_TYPE Py_UNICODE;

Py_UNICODEのサイズはデバッガで見ると2バイトとなっていた.これはPython内部の文字エンコーディングUCS-2が使われているためと考えられる.PY_UNICODE_TYPEは,PC/os2emx/pyconfig.h, PC/os2vacpp/pyconfig.h, Include/unicodeobject.hなどで定義されていたが,どれが使われているのか,ちょっと分からなかった.おそらく,wchar_tがPy_UNICODEの正体だろうと思われる.

これを踏まえると,Pythonでは0x7FFFFFFF - 1が文字列の最大長となることがわかる.-1としているのはNULL文字のためとなる.つまり,このif文は,確保しようとしている文字列の長さが最大長である0x7FFFFFFF - 1を超えていないかをチェックしており,越えていたらエラーとしてNULLを返しているに過ぎない.

フリーリスト

325〜342行のif文で内は,フリーリストからオブジェクトを取得している.普通,C言語ではメモリを確保するときはmalloc()を使い,そのメモリが必要なくなったらfree()で開放する必要がある.ところが,このfree()とmalloc()というのは比較的遅い(最近はかなり速いが).フリーリストでは,要らなくなったメモリはfree()を呼び出してすぐに開放する代わりに,フリーリストと呼ばれるリスト構造に保存しておいて,再び必要になったときはmalloc()ではなく,このフリーリストから取ってくるようにして,malloc()と,free()の呼び出し回数を減らしている.

PyUnicodeObjectのフリーリストは以下のように定義されている.

/* Objects/unicodeobject.c */
 106 /* Free list for Unicode objects */
 107 static PyUnicodeObject *free_list;
 108 static int numfree;

グローバル変数のfree_listがフリーリストで,num_freeがフリーリストにバッファされているオブジェクトの数となる.

フリーリストからオブジェクトを取り出す部分は以下の部分となる.

/* Objects/unicodeobject.c */
 309 PyUnicodeObject *_PyUnicode_New(Py_ssize_t length)
... /* 省略 */
 326         unicode = free_list;
 327         free_list = *(PyUnicodeObject **)unicode;
 328         numfree--;

326行目では,フリーリストの先頭からオブジェクトを取り出し,327行目でfree_listの値を更新している.327行目は若干分かりにくいが,実のところ

free_list = unicode->ob_base._ob_next;

としているだけである.フリーリストからオブジェクトを取り出したら,328行目でnum_freeがデクリメントされる.

329〜341行目は,実際に文字列を格納するためのバッファの確保を行っている.Pythonではフリーリストから取得したオブジェクトが,既に文字列用のバッファを持っていた場合realloc()を用いて,バッファサイズの変更を行う.ただし,バッファサイズの変更はバッファが足りない場合のみ,行われる.

unicode_resize()関数は,中でrealloc()を呼び出してバッファサイズを変更する関数である.確保に失敗すると,PyObject_DELマクロを呼び出しバッファを開放し,メンバ変数strにNULLを代入する.なおPyObject_DELマクロは,内部でfree()を呼び出しているだけのマクロである.ここでは,unicode_resize()関数とPyObject_DELマクロの詳細については割愛する.

もしも,文字列を格納するバッファが無かったら,すなわちメンバ変数strがNULLであったら,PyObject_MALLOCマクロを呼び出して確保する.なお,PyObject_MALLOCマクロは単にmalloc()関数をラッパしているだけである.

malloc()での確保

もしも,フリーリストが空であった場合は,malloc()を用いてPyUnicodeObject構造体のインスタンスを成功する.これは,345〜350行目となるが,ここでは,ただ単に必要なメモリ分をmalloc()関数で確保しているだけとなる.

今回のまとめ

今回の重要な点は,Pythonではmalloc()とfree()を呼び出す回数を減らすために,フリーリストを用いているということである.PyObject構造体の_ob_nextと_ob_prevというメンバ変数が,フリーリストに用いられる.

次回は,PyObject_INITマクロを追いかけて,Pythonのオブジェクトと型について詳しく見てみたい.