先來看它的定義
typedef struct _dictobject PyDictObject;
struct _dictobject {
PyObject_HEAD
Py_ssize_t ma_fill; /* # Active + # Dummy */
Py_ssize_t ma_used; /* # Active */
/* The table contains ma_mask + 1 slots, and that's a power of 2.
* We store the mask instead of the size because the mask is more
* frequently needed.
*/
Py_ssize_t ma_mask;
/* ma_table points to ma_smalltable for small tables, else to
* additional malloc'ed memory. ma_table is never NULL! This rule
* saves repeated runtime null-tests in the workhorse getitem and
* setitem calls.
*/
PyDictEntry *ma_table;
PyDictEntry *(*ma_lookup)(PyDictObject *mp, PyObject *key, Py_hash_t hash);
PyDictEntry ma_smalltable[PyDict_MINSIZE];
};
在PyObject *PyDict_New(void)中,調用了宏定義EMPTY_TO_MINSIZE
#define INIT_NONZERO_DICT_SLOTS(mp) do { \
(mp)->ma_table = (mp)->ma_smalltable; \
(mp)->ma_mask = PyDict_MINSIZE - 1; \
} while(0)
#define EMPTY_TO_MINSIZE(mp) do { \
memset((mp)->ma_smalltable, 0, sizeof((mp)->ma_smalltable)); \
(mp)->ma_used = (mp)->ma_fill = 0; \
INIT_NONZERO_DICT_SLOTS(mp); \
} while(0)
可以看出ma_table開始是指向ma_smalltable的,這和代碼的註釋一致
mp->ma_lookup = lookdict_unicode; 給函數指針賦值,dict的搜索函數
隨着int PyDict_SetItem(register PyObject *op, PyObject *key, PyObject *value)的不斷調用
該函數會在最後判斷
if (!(mp->ma_used > n_used && mp->ma_fill*3 >= (mp->ma_mask+1)*2))
return 0;
return dictresize(mp, (mp->ma_used > 50000 ? 2 : 4) * mp->ma_used);
可見在ma_fill = 6 && ma_mask=7 的時候,走到了dictresize
會重新申請新的內存, ma_table就不再指向ma_smalltable, 而是新的內存,
然後把原來老的內容拷貝到新的內存裏面.by calling insertdict_clean
之後 ma_fill = ma_used = 6, ma_mask = 31
/* Get space for a new table. */
oldtable = mp->ma_table;
assert(oldtable != NULL);
is_oldtable_malloced = oldtable != mp->ma_smalltable;
if (is_oldtable_malloced)
PyMem_DEL(oldtable);
最後看老的內存是否應該釋放
如果老的是ma_smalltable, 就不管了
Python源碼學習之初始化(三)-PyDictObject的初始化
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.