インターナル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()関数をラッパしているだけである.