欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

從Python的源碼淺要剖析Python的內(nèi)存管理

 更新時(shí)間:2015年04月16日 09:23:02   作者:dbzhang800  
這篇文章主要介紹了從Python的源碼淺要剖析Python的內(nèi)存管理,需要的朋友可以參考下

Python 的內(nèi)存管理架構(gòu)(Objects/obmalloc.c):

復(fù)制代碼 代碼如下:

    _____   ______   ______       ________
   [ int ] [ dict ] [ list ] ... [ string ]       Python core         |
+3 | <----- Object-specific memory -----> | <-- Non-object memory --> |
    _______________________________       |                           |
   [   Python's object allocator   ]      |                           |
+2 | ####### Object memory ####### | <------ Internal buffers ------> |
    ______________________________________________________________    |
   [          Python's raw memory allocator (PyMem_ API)          ]   |
+1 | <----- Python memory (under PyMem manager's control) ------> |   |
    __________________________________________________________________
   [    Underlying general-purpose allocator (ex: C library malloc)   ]
 0 | <------ Virtual memory allocated for the python process -------> |
 

    0. C語(yǔ)言庫(kù)函數(shù)提供的接口

    1. PyMem_*家族,是對(duì) C中的 malloc、realloc和free 簡(jiǎn)單的封裝,提供底層的控制接口。

    2. PyObject_* 家族,高級(jí)的內(nèi)存控制接口。
    3. 對(duì)象類型相關(guān)的管理接口

PyMem_*

PyMem_家族:低級(jí)的內(nèi)存分配接口(low-level memory allocation interfaces)

Python 對(duì)C中的 malloc、realloc和free 提供了簡(jiǎn)單的封裝:

201541692301579.jpg (301×158)

為什么要這么多次一舉:

  •     不同的C實(shí)現(xiàn)對(duì)于malloc(0)產(chǎn)生的結(jié)果有會(huì)所不同,而PyMem_MALLOC(0)會(huì)轉(zhuǎn)成malloc(1).
  •     不用的C實(shí)現(xiàn)的malloc與free混用會(huì)有潛在的問(wèn)題。python提供封裝可以避免這個(gè)問(wèn)題。
  •         Python提供了宏和函數(shù),但是宏無(wú)法避免這個(gè)問(wèn)題,故編寫擴(kuò)展是應(yīng)避免使用宏

源碼:

  Include/pymem.h

#define PyMem_MALLOC(n) ((size_t)(n) > (size_t)PY_SSIZE_T_MAX ? NULL \
             : malloc((n) ? (n) : 1))
#define PyMem_REALLOC(p, n) ((size_t)(n) > (size_t)PY_SSIZE_T_MAX ? NULL \
              : realloc((p), (n) ? (n) : 1))
#define PyMem_FREE free

  Objects/object.c

/* Python's malloc wrappers (see pymem.h) */

void *
PyMem_Malloc(size_t nbytes)
{
  return PyMem_MALLOC(nbytes);
}
...


除了對(duì)C的簡(jiǎn)單封裝外,Python還提供了4個(gè)宏

    PyMem_New 和 PyMem_NEW

    PyMem_Resize和 PyMem_RESIZE

它們可以感知類型的大小

#define PyMem_New(type, n) \
 ( ((size_t)(n) > PY_SSIZE_T_MAX / sizeof(type)) ? NULL :   \
    ( (type *) PyMem_Malloc((n) * sizeof(type)) ) )

#define PyMem_Resize(p, type, n) \
 ( (p) = ((size_t)(n) > PY_SSIZE_T_MAX / sizeof(type)) ? NULL :    \
    (type *) PyMem_Realloc((p), (n) * sizeof(type)) )
#define PyMem_Del        PyMem_Free
#define PyMem_DEL        PyMem_FREE


以下涉及的一些函數(shù)仍舊是函數(shù)和宏同時(shí)存在,下劃線后全是大寫字符的是宏,后面不再特別說(shuō)明。
PyObject_*

PyObject_*家族,是高級(jí)的內(nèi)存控制接口(high-level object memory interfaces)。

    注意

  •     不要和PyMem_*家族混用?。?/li>
  •     除非有特殊的內(nèi)粗管理要求,否則應(yīng)該堅(jiān)持使用PyObject_*

源碼

  Include/objimpl.h

#define PyObject_New(type, typeobj) \
        ( (type *) _PyObject_New(typeobj) )
#define PyObject_NewVar(type, typeobj, n) \
        ( (type *) _PyObject_NewVar((typeobj), (n)) )

  Objects/object.c

PyObject *
_PyObject_New(PyTypeObject *tp)
{
  PyObject *op;
  op = (PyObject *) PyObject_MALLOC(_PyObject_SIZE(tp));
  if (op == NULL)
    return PyErr_NoMemory();
  return PyObject_INIT(op, tp);
}

PyVarObject *
_PyObject_NewVar(PyTypeObject *tp, Py_ssize_t nitems)
{
  PyVarObject *op;
  const size_t size = _PyObject_VAR_SIZE(tp, nitems);
  op = (PyVarObject *) PyObject_MALLOC(size);
  if (op == NULL)
    return (PyVarObject *)PyErr_NoMemory();
  return PyObject_INIT_VAR(op, tp, nitems);
}

它們執(zhí)行兩項(xiàng)操作:

  1.     分配內(nèi)存:PyObject_MALLOC
  2.     部分初始化對(duì)象:PyObject_INIT和PyObject_INIT_VAR

初始化沒(méi)什么好看到,但是這個(gè)MALLOC就有點(diǎn)復(fù)雜無(wú)比了...
PyObject_{Malloc、Free}

這個(gè)和PyMem_*中的3個(gè)可是大不一樣了,復(fù)雜的厲害!

void * PyObject_Malloc(size_t nbytes)
void * PyObject_Realloc(void *p, size_t nbytes)
void PyObject_Free(void *p)

Python程序運(yùn)行時(shí)頻繁地需要?jiǎng)?chuàng)建和銷毀小對(duì)象,為了避免大量的malloc和free操作,Python使用了內(nèi)存池的技術(shù)。

  •     一系列的 arena(每個(gè)管理256KB) 構(gòu)成一個(gè)內(nèi)存區(qū)域的鏈表
  •     每個(gè) arena 有很多個(gè) pool(每個(gè)4KB) 構(gòu)成
  •     每次內(nèi)存的申請(qǐng)釋放將在一個(gè) pool 內(nèi)進(jìn)行

單次申請(qǐng)內(nèi)存塊

當(dāng)申請(qǐng)大小在 1~256 字節(jié)之間的內(nèi)存時(shí),使用內(nèi)存池(申請(qǐng)0或257字節(jié)以上時(shí),將退而使用我們前面提到的PyMem_Malloc)。

每次申請(qǐng)時(shí),實(shí)際分配的空間將按照某個(gè)字節(jié)數(shù)對(duì)齊,下表中為8字節(jié)(比如PyObject_Malloc(20)字節(jié)將分配24字節(jié))。

復(fù)制代碼 代碼如下:

Request in bytes     Size of allocated block      Size class idx
  ----------------------------------------------------------------
         1-8                     8                       0
         9-16                   16                       1
        17-24                   24                       2
        25-32                   32                       3
        33-40                   40                       4
         ...                   ...                     ...
       241-248                 248                      30
       249-256                 256                      31
 
       0, 257 and up: routed to the underlying allocator.
      

這些參數(shù)由一些宏進(jìn)行控制:

#define ALIGNMENT        8        /* must be 2^N */
/* Return the number of bytes in size class I, as a uint. */
#define INDEX2SIZE(I) (((uint)(I) + 1) << ALIGNMENT_SHIFT)
#define SMALL_REQUEST_THRESHOLD 256

pool

每次申請(qǐng)的內(nèi)存塊都是需要在 pool 中進(jìn)行分配,一個(gè)pool的大小是 4k。由下列宏進(jìn)行控制:

#define SYSTEM_PAGE_SIZE        (4 * 1024)
#define POOL_SIZE               SYSTEM_PAGE_SIZE        /* must be 2^N */

每個(gè)pool的頭部的定義如下:

struct pool_header {
  union { block *_padding;
      uint count; } ref;     /* number of allocated blocks  */
  block *freeblock;          /* pool's free list head     */
  struct pool_header *nextpool;    /* next pool of this size class */
  struct pool_header *prevpool;    /* previous pool    ""    */
  uint arenaindex;          /* index into arenas of base adr */
  uint szidx;             /* block size class index    */
  uint nextoffset;          /* bytes to virgin block     */
  uint maxnextoffset;         /* largest valid nextoffset   */
};

注意,其中有個(gè)成員 szidx,對(duì)應(yīng)前面列表中最后一列的 Size class idx。這也說(shuō)明一個(gè)問(wèn)題:每個(gè) pool 只能分配固定大小的內(nèi)存塊(比如,只分配16字節(jié)的塊,或者只分配24字節(jié)的塊...)。

要能分配前面列表中各種大小的內(nèi)存塊,必須有多個(gè) pool。同一大小的pool分配完畢,也需要新的pool。多個(gè)pool依次構(gòu)成一個(gè)鏈表
arena

多個(gè)pool對(duì)象使用被稱為 arena 的東西進(jìn)行管理。

struct arena_object {
  uptr address;
  block* pool_address;
  uint nfreepools;
  uint ntotalpools;
  struct pool_header* freepools;
  struct arena_object* nextarena;
  struct arena_object* prevarena;
};

arean控制的內(nèi)存的大小由下列宏控制:

#define ARENA_SIZE       (256 << 10)   /* 256KB */

一系列的 arena 構(gòu)成一個(gè)鏈表。
引用計(jì)數(shù)與垃圾收集

Python中多數(shù)對(duì)象的生命周期是通過(guò)引用計(jì)數(shù)來(lái)控制的,從而實(shí)現(xiàn)了內(nèi)存的動(dòng)態(tài)管理。

但是引用計(jì)數(shù)有一個(gè)致命的問(wèn)題:循環(huán)引用!

為了打破循環(huán)引用,Python引入了垃圾收集技術(shù)。

相關(guān)文章

  • python操作excel之openpyxl模塊讀寫xlsx格式使用方法詳解

    python操作excel之openpyxl模塊讀寫xlsx格式使用方法詳解

    這篇文章主要介紹了python操作excel之openpyxl模塊讀寫xlsx格式使用方法詳解,需要的朋友可以參考下
    2022-12-12
  • 對(duì)TensorFlow中的variables_to_restore函數(shù)詳解

    對(duì)TensorFlow中的variables_to_restore函數(shù)詳解

    今天小編就為大家分享一篇對(duì)TensorFlow中的variables_to_restore函數(shù)詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-07-07
  • python運(yùn)行腳本文件的三種方法實(shí)例

    python運(yùn)行腳本文件的三種方法實(shí)例

    在計(jì)算中,腳本一詞用于指代包含訂單邏輯序列的文件或批處理文件,下面這篇文章主要給大家介紹了關(guān)于python運(yùn)行腳本文件的三種方法,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-06-06
  • 對(duì)numpy的array和python中自帶的list之間相互轉(zhuǎn)化詳解

    對(duì)numpy的array和python中自帶的list之間相互轉(zhuǎn)化詳解

    下面小編就為大家分享一篇對(duì)numpy的array和python中自帶的list之間相互轉(zhuǎn)化詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-04-04
  • django 中的聚合函數(shù),分組函數(shù),F(xiàn) 查詢,Q查詢

    django 中的聚合函數(shù),分組函數(shù),F(xiàn) 查詢,Q查詢

    這篇文章主要介紹了django 中的聚合函數(shù),分組函數(shù),F(xiàn) 查詢,Q查詢,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-07-07
  • Win10下安裝CUDA11.0+CUDNN8.0+tensorflow-gpu2.4.1+pytorch1.7.0+paddlepaddle-gpu2.0.0

    Win10下安裝CUDA11.0+CUDNN8.0+tensorflow-gpu2.4.1+pytorch1.7.0+p

    這篇文章主要介紹了Win10下安裝CUDA11.0+CUDNN8.0+tensorflow-gpu2.4.1+pytorch1.7.0+paddlepaddle-gpu2.0.0,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • Python制作簡(jiǎn)易版小工具之計(jì)算天數(shù)的實(shí)現(xiàn)思路

    Python制作簡(jiǎn)易版小工具之計(jì)算天數(shù)的實(shí)現(xiàn)思路

    這篇文章主要介紹了Python制作簡(jiǎn)易版小工具之計(jì)算天數(shù)的實(shí)現(xiàn)思路,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-02-02
  • 利用Python和C語(yǔ)言分別實(shí)現(xiàn)哈夫曼編碼

    利用Python和C語(yǔ)言分別實(shí)現(xiàn)哈夫曼編碼

    這篇文章主要為大家詳細(xì)介紹了如何利用Python和C語(yǔ)言分別實(shí)現(xiàn)哈夫曼編碼,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2022-07-07
  • python中torch可以成功引用但無(wú)法訪問(wèn)屬性的解決辦法

    python中torch可以成功引用但無(wú)法訪問(wèn)屬性的解決辦法

    這篇文章給大家介紹了我們?cè)趐ython中運(yùn)行程序時(shí)遇到一個(gè)奇怪的報(bào)錯(cuò),torch可以成功引用但無(wú)法訪問(wèn)屬性,這是比較奇怪的一件事,因?yàn)閠orch肯定是可以訪問(wèn)Tensor,所以本文給大家介紹了torch可以成功引用但無(wú)法訪問(wèn)屬性的解決辦法,需要的朋友可以參考下
    2024-01-01
  • Python的Dict對(duì)象源碼分析

    Python的Dict對(duì)象源碼分析

    這篇文章主要介紹了Python的Dict對(duì)象源碼分析,PyDictObject即字典對(duì)象,類似于C++ STL中的map,但STL中以紅黑樹實(shí)現(xiàn),Python中dict以hash表(散列表)實(shí)現(xiàn),需要的朋友可以參考下
    2023-08-08

最新評(píng)論