中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

python的內存回收機制是什么

發布時間:2023-04-21 17:07:50 來源:億速云 閱讀:126 作者:iii 欄目:開發技術

這篇“python的內存回收機制是什么”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“python的內存回收機制是什么”文章吧。

一:建立對象引用計數

1. 相關代碼

void
_Py_NewReference(PyObject *op)
{
    if (_Py_tracemalloc_config.tracing) {
        _PyTraceMalloc_NewReference(op);
    }
#ifdef Py_REF_DEBUG
    _Py_RefTotal++;
#endif
    Py_SET_REFCNT(op, 1);
#ifdef Py_TRACE_REFS
    _Py_AddToAllObjects(op, 1);
#endif
}

2. 代碼解釋

_Py_NewReference這個函數的主要目的是為新創建的Python對象建立引用計數。在CPython中,引用計數是用來管理內存的一種方法,當一個Python對象的引用計數變為零時,表示沒有其他對象引用該對象,因此可以安全地將其內存回收。

下面是_Py_NewReference函數的各個部分的簡要說明:

  1. _Py_tracemalloc_config.tracing:當內存追蹤功能啟用時(即_Py_tracemalloc_config.tracing為真),調用_PyTraceMalloc_NewReference(op)以記錄新引用的內存分配。

  2. #ifdef Py_REF_DEBUG:如果啟用了引用計數調試(即編譯時定義了Py_REF_DEBUG),則增加全局引用計數_Py_RefTotal。

  3. Py_SET_REFCNT(op, 1):將新對象op的引用計數設置為1。

  4. #ifdef Py_TRACE_REFS:如果啟用了引用跟蹤功能(即編譯時定義了Py_TRACE_REFS),則調用_Py_AddToAllObjects(op, 1)將新對象op添加到所有對象列表中以進行跟蹤。

這個函數通常在創建新的Python對象時調用,以便正確初始化引用計數。需要注意的是,這個函數是CPython內部使用的,不應該在普通Python代碼或擴展模塊中直接使用。

#ifdef Py_REF_DEBUG是一個C預處理器指令,它會檢查是否在編譯時定義了Py_REF_DEBUG宏。如果定義了這個宏,那么在#ifdef#endif之間的代碼塊將被編譯并包含在最終的程序中。否則,這部分代碼將被忽略。

Py_REF_DEBUG宏用于啟用引用計數調試功能。這個功能允許CPython開發者和擴展模塊開發者在開發過程中更輕松地追蹤和診斷潛在的引用計數錯誤。這對于調試內存泄漏或提前釋放對象等問題非常有用。

當啟用Py_REF_DEBUG時,_Py_RefTotal變量被用來跟蹤當前分配給Python對象的總引用計數。這個全局計數器在每次創建新引用(如在_Py_NewReference函數中)時遞增,在釋放引用時遞減。通過檢查_Py_RefTotal的值,開發者可以在某些情況下發現可能的內存泄漏或錯誤的引用計數操作。

需要注意的是,Py_REF_DEBUG功能會帶來一定的性能開銷,因此在生產環境中通常不啟用。在發布構建中,默認情況下不會定義Py_REF_DEBUG宏。在開發和調試階段,可以通過配置構建選項來啟用這個功能。

二: 引用計數增加

1. 相關源碼

// 引用計數增加
void
Py_IncRef(PyObject *o)
{
    Py_XINCREF(o);
}

// 宏定義
#define Py_XINCREF(op) _Py_XINCREF(_PyObject_CAST(op))

// 內聯函數
static inline void _Py_XINCREF(PyObject *op)
{
    if (op != NULL) {
        Py_INCREF(op);
    }
}

// 宏定義
#define Py_INCREF(op) _Py_INCREF(_PyObject_CAST(op))

static inline void _Py_INCREF(PyObject *op)
{
#ifdef Py_REF_DEBUG
    _Py_RefTotal++;
#endif
    op->ob_refcnt++;  // 對象的引用計數加1
}

2. 源碼解釋

_Py_INCREF函數是一個靜態內聯函數,用于增加給定Python對象(op)的引用計數。內聯函數允許編譯器在調用處內聯展開函數體,以減少函數調用的開銷。以下是_Py_INCREF函數的各個部分的簡要說明:

#ifdef Py_REF_DEBUG:如果啟用了引用計數調試(即編譯時定義了Py_REF_DEBUG),則增加全局引用計數_Py_RefTotalop->ob_refcnt++:增加給定Python對象op的引用計數(ob_refcnt字段)。

Py_INCREF是一個宏,用于調用_Py_INCREF函數。在調用_Py_INCREF之前,它首先使用_PyObject_CAST宏將給定的對象(op)轉換為PyObject指針。這是為了確保_Py_INCREF函數接收到的參數具有正確的類型。在編寫Python C擴展時,通常會使用Py_INCREF宏來增加Python對象的引用計數。

三:引用計數減少

1. 相關源碼

void
Py_DecRef(PyObject *o)
{
    Py_XDECREF(o);
}

#define Py_XDECREF(op) _Py_XDECREF(_PyObject_CAST(op))

static inline void _Py_XDECREF(PyObject *op)
{
    if (op != NULL) {
        Py_DECREF(op);
    }
}

define Py_DECREF(op) _Py_DECREF(_PyObject_CAST(op))

static inline void _Py_DECREF(
#ifdef Py_REF_DEBUG
    const char *filename, int lineno,
#endif
    PyObject *op)
{
#ifdef Py_REF_DEBUG
    _Py_RefTotal--;
#endif
    if (--op->ob_refcnt != 0) {
#ifdef Py_REF_DEBUG
        if (op->ob_refcnt < 0) {
            _Py_NegativeRefcount(filename, lineno, op);
        }
#endif
    }
    else {
        _Py_Dealloc(op);
    }
}

// 引用計數等于0了,就調用dealloc函數進行對象刪除
void
_Py_Dealloc(PyObject *op)
{
    destructor dealloc = Py_TYPE(op)->tp_dealloc;
#ifdef Py_TRACE_REFS
    _Py_ForgetReference(op);
#endif
    (*dealloc)(op);
}

2. 源碼解釋

在這段代碼中,我們可以看到Py_DecRefPy_XDECREF_Py_XDECREFPy_DECREF_Py_DECREF這幾個用于處理Python對象引用計數的函數和宏。

  1. Py_DecRef:這是一個簡單的封裝函數,接受一個指向PyObject的指針o作為參數,然后調用Py_XDECREF(o)宏。

  2. Py_XDECREF:這是一個宏,用于調用_Py_XDECREF函數。在調用之前,它使用_PyObject_CAST(op)宏將給定的對象(op)轉換為PyObject指針。

  3. _Py_XDECREF:這是一個靜態內聯函數,用于在給定對象不為NULL時調用Py_DECREF宏。這意味著如果對象指針為空(即op == NULL),則不會對引用計數進行任何操作。

  4. Py_DECREF:這是一個宏,用于調用_Py_DECREF函數。在調用之前,它使用_PyObject_CAST(op)宏將給定的對象(op)轉換為PyObject指針。

  5. _Py_DECREF:這是一個靜態內聯函數,用于減少給定Python對象(op)的引用計數。以下是_Py_DECREF函數的各個部分的簡要說明:

a. #ifdef Py_REF_DEBUG:如果啟用了引用計數調試(即編譯時定義了Py_REF_DEBUG),則減少全局引用計數_Py_RefTotal

b. 減少對象的引用計數:使用--op->ob_refcnt來減少給定對象op的引用計數。

c. 判斷引用計數是否為0:如果引用計數不為0,表示仍有其他對象引用該對象。如果引用計數為0,則調用_Py_Dealloc(op)來釋放對象的內存。在引用計數調試模式下,還會檢查引用計數是否為負數,如果是,則調用_Py_NegativeRefcount(filename, lineno, op)報告錯誤。

在Python C擴展中,通常使用Py_DECREFPy_XDECREF宏來減少Python對象的引用計數。這些宏提供了安全和高效的方式來處理引用計數,以防止內存泄漏和提前釋放對象。

四:對象刪除

1. 相關源碼

void
_Py_Dealloc(PyObject *op)
{
    destructor dealloc = Py_TYPE(op)->tp_dealloc;
#ifdef Py_TRACE_REFS
    _Py_ForgetReference(op);
#endif
    (*dealloc)(op);
}

2. 源碼解釋

_Py_Dealloc函數是CPython中用于釋放Python對象內存的函數。它在對象的引用計數變為零時調用,表示沒有其他對象引用該對象,可以安全地回收其內存。以下是_Py_Dealloc函數的各個部分的簡要說明:

destructor dealloc = Py_TYPE(op)->tp_dealloc;:從給定Python對象op的類型對象中獲取析構函數(tp_dealloc),并將其賦值給dealloc。每個類型對象都有一個與之關聯的析構函數,該函數負責清理該類型的對象所占用的內存。#ifdef Py_TRACE_REFS:如果啟用了引用跟蹤功能(即編譯時定義了Py_TRACE_REFS),則調用_Py_ForgetReference(op)將對象op從所有對象列表中刪除,以便不再跟蹤該對象。(*dealloc)(op);:調用dealloc指向的析構函數,釋放對象op所占用的內存。這里使用了函數指針,這意味著dealloc可以指向任何類型的析構函數,從而可以靈活地處理不同類型的Python對象。

需要注意的是,_Py_Dealloc函數是CPython內部使用的,不應該在普通Python代碼或擴展模塊中直接使用。在Python擴展模塊中,您應該使用相應的宏和API函數來管理引用計數,例如Py_DECREFPy_XDECREF

Py_TYPE(op)是一個宏,用于獲取給定Python對象(op)的類型。它返回一個指向PyTypeObject結構的指針,這個結構包含了對象類型的相關信息,如類型名、方法、屬性、析構函數等。

在CPython內部實現中,每個Python對象都包含一個指向其類型對象的指針。這個指針位于PyObject結構的ob_type字段中。Py_TYPE(op)宏實際上就是訪問這個ob_type字段,即op->ob_type

在Python C擴展和嵌入式代碼中,Py_TYPE(op)宏可以用于檢查對象的類型、獲取類型特定的函數或執行類型相關的操作。例如,可以通過比較兩個對象的類型對象來判斷它們是否屬于相同的類型。

以上就是關于“python的內存回收機制是什么”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

荃湾区| 汉中市| 金沙县| 昭苏县| 五峰| 西乡县| 娱乐| 定结县| 淮阳县| 东港市| 仲巴县| 额尔古纳市| 阿拉尔市| 牡丹江市| 衡水市| 洪江市| 惠东县| 长子县| 海兴县| 万荣县| 通河县| 吴忠市| 繁峙县| 应用必备| 溧水县| 苍南县| 天长市| 永昌县| 云林县| 兴海县| 绿春县| 大理市| 瓦房店市| 确山县| 锡林浩特市| 株洲县| 穆棱市| 青龙| 苍南县| 香格里拉县| 新化县|