最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python的內(nèi)存泄漏及gc模塊的使用分析

 更新時間:2014年07月16日 11:02:51   投稿:shichen2014  
這篇文章主要介紹了Python的內(nèi)存泄漏及gc模塊的使用分析,有助于讀者進(jìn)一步了解Python的內(nèi)存分配及回收機(jī)制,增強(qiáng)代碼編寫的安全意識,需要的朋友可以參考下

一般來說在 Python 中,為了解決內(nèi)存泄漏問題,采用了對象引用計數(shù),并基于引用計數(shù)實現(xiàn)自動垃圾回收。
由于Python 有了自動垃圾回收功能,就造成了不少初學(xué)者誤認(rèn)為自己從此過上了好日子,不必再受內(nèi)存泄漏的騷擾了。但如果仔細(xì)查看一下Python文檔對 __del__() 函數(shù)的描述,就知道這種好日子里也是有陰云的。下面摘抄一點文檔內(nèi)容如下:

Some common situations that may prevent the reference count of an object from going to zero include: circular references between objects (e.g., a doubly-linked list or a tree data structure with parent and child pointers); a reference to the object on the stack frame of a function that caught an exception (the traceback stored in sys.exc_traceback keeps the stack frame alive); or a reference to the object on the stack frame that raised an unhandled exception in interactive mode (the traceback stored in sys.last_traceback keeps the stack frame alive).

可見,有 __del__() 函數(shù)的對象間的循環(huán)引用是導(dǎo)致內(nèi)存泄漏的主兇。
另外需要說明:對沒有 __del__() 函數(shù)的 Python 對象間的循環(huán)引用,是可以被自動垃圾回收掉的。

如何知道一個對象是否內(nèi)存泄漏了呢?

方法一、當(dāng)你認(rèn)為一個對象應(yīng)該被銷毀時(即引用計數(shù)為 0),可以通過 sys.getrefcount(obj) 來獲取對象的引用計數(shù),并根據(jù)返回值是否為 0 來判斷是否內(nèi)存泄漏。如果返回的引用計數(shù)不為 0,說明在此刻對象 obj 是不能被垃圾回收器回收掉的。

方法二、也可以通過 Python 擴(kuò)展模塊 gc 來查看不能回收的對象的詳細(xì)信息。


首先,來看一段正常的測試代碼:

#--------------- code begin --------------
# -*- coding: utf-8 -*-
import gc
import sys

class CGcLeak(object):
  def __init__(self):
    self._text = '#'*10

  def __del__(self):
    pass

def make_circle_ref():
  _gcleak = CGcLeak()
#  _gcleak._self = _gcleak # test_code_1
  print '_gcleak ref count0:%d' % sys.getrefcount(_gcleak)
  del _gcleak
  try:
    print '_gcleak ref count1:%d' % sys.getrefcount(_gcleak)
  except UnboundLocalError:
    print '_gcleak is invalid!'

def test_gcleak():
  # Enable automatic garbage collection.
  gc.enable()
  # Set the garbage collection debugging flags.
  gc.set_debug(gc.DEBUG_COLLECTABLE | gc.DEBUG_UNCOLLECTABLE | /
    gc.DEBUG_INSTANCES | gc.DEBUG_OBJECTS)

  print 'begin leak test...'
  make_circle_ref()

  print 'begin collect...'
  _unreachable = gc.collect()
  print 'unreachable object num:%d' % _unreachable
  print 'garbage object num:%d' % len(gc.garbage)

if __name__ == '__main__':
  test_gcleak()

在 test_gcleak() 中,設(shè)置垃圾回收器調(diào)試標(biāo)志后,再用 collect() 進(jìn)行垃圾回收,最后打印出該次垃圾回收發(fā)現(xiàn)的不可達(dá)的垃圾對象數(shù)和整個解釋器中的垃圾對象數(shù)。

gc.garbage 是一個 list 對象,列表項是垃圾收集器發(fā)現(xiàn)的不可達(dá)(即是垃圾對象)、但又不能釋放(即不能回收)的對象。文檔描述為:A list of objects which the collector found to be unreachable but could not be freed (uncollectable objects).
通常,gc.garbage 中的對象是引用環(huán)中的對象。因為 Python 不知道按照什么樣的安全次序來調(diào)用環(huán)中對象的 __del__() 函數(shù),導(dǎo)致對象始終存活在 gc.garbage 中,造成內(nèi)存泄漏。如果知道一個安全的次序,那么就打破引用環(huán),再執(zhí)行 del gc.garbage[:] ,以清空垃圾對象列表。

上段代碼輸出為(#后字符串為筆者所加注釋):

#-----------------------------------------
begin leak test...
# 變量 _gcleak 的引用計數(shù)為 2.
_gcleak ref count0:2
# _gcleak 變?yōu)椴豢蛇_(dá)(unreachable)的非法變量.
_gcleak is invalid!
# 開始垃圾回收
begin collect...
# 本次垃圾回收發(fā)現(xiàn)的不可達(dá)的垃圾對象數(shù)為 0.
unreachable object num:0
# 整個解釋器中的垃圾對象數(shù)為 0.
garbage object num:0
#-----------------------------------------

由此可見 _gcleak 對象的引用計數(shù)是正確的,也沒有任何對象發(fā)生內(nèi)存泄漏。

如果不注釋掉 make_circle_ref() 中的 test_code_1 語句:

_gcleak._self = _gcleak

也就是讓 _gcleak 形成一個自己對自己的循環(huán)引用。再運(yùn)行上述代碼,輸出結(jié)果就變成:

#-----------------------------------------
begin leak test...
_gcleak ref count0:3
_gcleak is invalid!
begin collect...
# 發(fā)現(xiàn)可以回收的垃圾對象: 地址為 012AA090,類型為 CGcLeak.
gc: uncollectable <CGcLeak 012AA090>
gc: uncollectable <dict 012AC1E0>
unreachable object num:2
#!! 不能回收的垃圾對象數(shù)為 1,導(dǎo)致內(nèi)存泄漏!
garbage object num:1
#-----------------------------------------

可見 <CGcLeak 012AA090> 對象發(fā)生了內(nèi)存泄漏??!而多出的 dict 垃圾就是泄漏的 _gcleak 對象的字典,打印出字典信息為:

{'_self': <__main__.CGcLeak object at 0x012AA090>, '_text': '##########'}

除了對自己的循環(huán)引用,多個對象間的循環(huán)引用也會導(dǎo)致內(nèi)存泄漏。簡單舉例如下:

#--------------- code begin --------------

class CGcLeakA(object):
  def __init__(self):
    self._text = '#'*10

  def __del__(self):
    pass

class CGcLeakB(object):
  def __init__(self):
    self._text = '*'*10

  def __del__(self):
    pass

def make_circle_ref():
  _a = CGcLeakA()
  _b = CGcLeakB()
  _a._b = _b # test_code_2
  _b._a = _a # test_code_3
  print 'ref count0:a=%d b=%d' % /
    (sys.getrefcount(_a), sys.getrefcount(_b))
#  _b._a = None  # test_code_4
  del _a
  del _b
  try:
    print 'ref count1:a=%d' % sys.getrefcount(_a)
  except UnboundLocalError:
    print '_a is invalid!'
  try:
    print 'ref count2:b=%d' % sys.getrefcount(_b)
  except UnboundLocalError:
    print '_b is invalid!'

#--------------- code end ----------------

這次測試后輸出結(jié)果為:

#-----------------------------------------
begin leak test...
ref count0:a=3 b=3
_a is invalid!
_b is invalid!
begin collect...
gc: uncollectable <CGcLeakA 012AA110>
gc: uncollectable <CGcLeakB 012AA0B0>
gc: uncollectable <dict 012AC1E0>
gc: uncollectable <dict 012AC0C0>
unreachable object num:4
garbage object num:2
#-----------------------------------------

可見 _a,_b 對象都發(fā)生了內(nèi)存泄漏。因為二者是循環(huán)引用,垃圾回收器不知道該如何回收,也就是不知道該首先調(diào)用那個對象的 __del__() 函數(shù)。

采用以下任一方法,打破環(huán)狀引用,就可以避免內(nèi)存泄漏:

1.注釋掉 make_circle_ref() 中的 test_code_2 語句;
2.注釋掉 make_circle_ref() 中的 test_code_3 語句;
3.取消對 make_circle_ref() 中的 test_code_4 語句的注釋。

相應(yīng)輸出結(jié)果變?yōu)椋?/p>

#-----------------------------------------
begin leak test...
ref count0:a=2 b=3 # 注:此處輸出結(jié)果視情況變化.
_a is invalid!
_b is invalid!
begin collect...
unreachable object num:0
garbage object num:0
#-----------------------------------------

結(jié)論:Python 的 gc 有比較強(qiáng)的功能,比如設(shè)置 gc.set_debug(gc.DEBUG_LEAK) 就可以進(jìn)行循環(huán)引用導(dǎo)致的內(nèi)存泄露的檢查。如果在開發(fā)時進(jìn)行內(nèi)存泄露檢查;在發(fā)布時能夠確保不會內(nèi)存泄露,那么就可以延長 Python 的垃圾回收時間間隔、甚至主動關(guān)閉垃圾回收機(jī)制,從而提高運(yùn)行效率。

相關(guān)文章

  • Python統(tǒng)計節(jié)假日剩余天數(shù)的腳本

    Python統(tǒng)計節(jié)假日剩余天數(shù)的腳本

    過完春節(jié),盼著下一個節(jié)日,那么如何判斷距離節(jié)假日還有多少天呢?今天小編給大家介紹使用python腳本來解決這個問題,對Python統(tǒng)計節(jié)假日倒計時腳本感興趣的朋友一起看看吧
    2022-02-02
  • python調(diào)用fortran模塊

    python調(diào)用fortran模塊

    本文給大家介紹的是在Python中調(diào)用fortran代碼,主要是用到了f2py這個程序,十分的實用,有需要的小伙伴可以參考下
    2016-04-04
  • python爬取網(wǎng)頁轉(zhuǎn)換為PDF文件

    python爬取網(wǎng)頁轉(zhuǎn)換為PDF文件

    這篇文章主要為大家詳細(xì)介紹了python爬取網(wǎng)頁轉(zhuǎn)換為PDF文件,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-06-06
  • Python中低維數(shù)組填充高維數(shù)組的實現(xiàn)

    Python中低維數(shù)組填充高維數(shù)組的實現(xiàn)

    今天小編就為大家分享一篇Python中低維數(shù)組填充高維數(shù)組的實現(xiàn),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-12-12
  • python使用正則表達(dá)式替換匹配成功的組

    python使用正則表達(dá)式替換匹配成功的組

    正則表達(dá)式,又稱正規(guī)表示式、正規(guī)表示法、正規(guī)表達(dá)式、規(guī)則表達(dá)式、常規(guī)表示法。這篇文章主要介紹了python里使用正則表達(dá)式來替換匹配成功的組,需要的朋友可以參考下
    2017-11-11
  • arcgis使用Python腳本進(jìn)行批量截圖功能實現(xiàn)

    arcgis使用Python腳本進(jìn)行批量截圖功能實現(xiàn)

    最近公司數(shù)據(jù)部那邊有個需求,需要結(jié)合矢量數(shù)據(jù)和影像數(shù)據(jù),進(jìn)行批量截圖,并且截圖中只能有一個圖斑,還要添加上相應(yīng)的水印,這篇文章主要介紹了arcgis使用Python腳本進(jìn)行批量截圖,需要的朋友可以參考下
    2023-01-01
  • python十進(jìn)制轉(zhuǎn)二進(jìn)制的詳解

    python十進(jìn)制轉(zhuǎn)二進(jìn)制的詳解

    在本篇文章里小編給大家整理了關(guān)于python十進(jìn)制轉(zhuǎn)二進(jìn)制的相關(guān)知識點內(nèi)容,需要的朋友們可以參考學(xué)習(xí)下。
    2020-02-02
  • OpenCV全景圖像拼接的實現(xiàn)示例

    OpenCV全景圖像拼接的實現(xiàn)示例

    opencv其實自己就有實現(xiàn)圖像拼接的算法,當(dāng)然效果也是相當(dāng)好的,本文主要介紹了OpenCV全景圖像拼接,感興趣的可以一起來了解一下
    2021-06-06
  • Python的10道簡單測試題(含答案)

    Python的10道簡單測試題(含答案)

    這篇文章主要介紹了Python的10道簡單測試題(含答案),學(xué)習(xí)了一段時間python的小伙伴來做幾道測試題檢驗一下自己的學(xué)習(xí)成果吧
    2023-04-04
  • Pandas數(shù)據(jù)如何讀取與導(dǎo)出

    Pandas數(shù)據(jù)如何讀取與導(dǎo)出

    Pandas是一個強(qiáng)大的Python庫,用于數(shù)據(jù)處理和分析,它提供了多種文件格式的數(shù)據(jù)讀取和導(dǎo)出方法,包括CSV、Excel、SQL數(shù)據(jù)庫、JSON等,常用的數(shù)據(jù)讀取方法為`pd.read_csv()`、`pd.read_excel()`等,導(dǎo)出方法為`to_csv()`、`to_excel()`等
    2025-01-01

最新評論

雷山县| 高密市| 静海县| 诸城市| 赤水市| 潞城市| 临朐县| 石狮市| 綦江县| 滦南县| 彩票| 寿阳县| 土默特右旗| 台南市| 金秀| 沿河| 彭阳县| 香港 | 额尔古纳市| 茶陵县| 蒙城县| 盘山县| 定日县| 丘北县| 铜梁县| 闻喜县| 旺苍县| 福建省| 延吉市| 高阳县| 米泉市| 巨野县| 阿鲁科尔沁旗| 苗栗县| 蒙城县| 重庆市| 庆元县| 全州县| 宝应县| 枝江市| 玛沁县|