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

粗略分析Python中的內(nèi)存泄漏

 更新時間:2015年04月23日 16:37:41   作者:C Wong  
這篇文章主要介紹了粗略分析Python中的內(nèi)存泄漏,分析了包括在垃圾回收時產(chǎn)生等的原因,需要的朋友可以參考下

引子

之前一直盲目的認為 Python 不會存在內(nèi)存泄露, 但是眼看著上線的項目隨著運行時間的增長 而越來越大的內(nèi)存占用, 我意識到我寫的程序在發(fā)生內(nèi)存泄露, 之前 debug 過 logging 模塊導致的內(nèi)存泄露.

目前看來, 還有別的地方引起的內(nèi)存泄露. 經(jīng)過一天的奮戰(zhàn), 終于找到了內(nèi)存泄露的地方, 目前項目 跑了很長時間, 在業(yè)務(wù)量較小的時候內(nèi)存還是能回到剛啟動的時候的內(nèi)存占用.
什么情況下不用這么麻煩

如果你的程序只是跑一下就退出大可不必大費周章的去查找是否有內(nèi)存泄露, 因為 Python 在退出時 會釋放它所分配的所有內(nèi)存, 如果你的程序需要連續(xù)跑很長時間那么就要仔細的查找是否 產(chǎn)生了內(nèi)存泄露.
場景

如何產(chǎn)生的內(nèi)存泄露呢, 項目是一個 TCP server, 每當有連接過來時都會創(chuàng)建一個連接實例來進行 管理, 每次斷開時連接實例還被占用并沒有釋放. 沒有被釋放的原因肯定是因為有某個地方對連接 實例的引用沒有釋放, 所以隨著時間的推移, 連接創(chuàng)建分配內(nèi)存, 連接斷開并沒有釋放掉內(nèi)存, 所以 就會產(chǎn)生內(nèi)存泄露.
調(diào)試方法

由于不知道具體是哪里引起的內(nèi)存泄露, 所以要耐心的一點點調(diào)試.

由于知道了斷開連接時沒有釋放, 所以我就不停的模擬創(chuàng)建連接然后發(fā)送一些包后斷開連接, 然后通過下面一行 shell 來觀察內(nèi)存占用情況:

PID=50662;while true; do; ps aux | grep $PID | grep -v grep | awk '{print $5" "$6}' >> t; sleep 1; done

如果在增長了一定的量后保持住就說明已經(jīng)沒有產(chǎn)生泄露.

同時可以在對象該釋放的時候查看對象的引用計數(shù), 通過 sys.getrefcount(obj). 如果引用計數(shù)變?yōu)榱?2 則說明該對象在跳出命名空間后就會被正確回收.
產(chǎn)生原因

項目中兩種情況導致對象沒有被正確回收:

  •     被退出才回收的對象引用
  •     交叉引用

被退出才回收的對象引用

為了追蹤連接所以把連接對象同時放在一個列表里, 而這個列表只有在程序退出時才會被回收, 如果不正確處理, 那么分配的對象將也會只在程序退出時才會被回收.

全局變量和類變量都只會在程序退出的時候才會被回收:

_CONNECTIONS = []

# ...
class Connection(object):
 def __init__(self, sock, address)
  pass

def server_loop():
 # ...
 sock, address = server_sock.accept()
 connection = Connection(sock, address)
 _CONNECTIONS.append(connection)
 # ...
 sock.close()

上面把所有建立的連接都放在全局變量 _CONNECTIONS 里, 如果在關(guān)閉的時候不從這個列表 里取出(減少引用)則 connection 對象就不會被回收, 則每建立一次連接就會有個連接對象和連接 對象引用的對象不會被回收.

如果把對象放在一個類屬性里也是一樣的, 因為類對象在程序一開始就分配, 并在程序退出時才被回收.

解決辦法就是在退出時從列表(或其他對象)里解除對對象的引用(刪除)

_CONNECTIONS = []

# ...
class Connection(object):
 def __init__(self, sock, address)
  pass

def server_loop():
 # ...
 sock, address = server_sock.accept()
 connection = Connection(sock, address)
 _CONNECTIONS.append(connection)
 try:
  # ...
  sock.close()
 finally:
  _CONNECTIONS.remove(connection) # XXX

交叉引用

有時候我們?yōu)閷ο蠓峙湟粋€實例屬性時需要將自己本身賦值給實例屬性, 作為實例屬性的實例屬性, 說著很拗口, 看一下代碼:

class ConnectionHandler(object):
 def __init__(self, connection):
  self._conn = connection


class Connection(object):
 def __init__(self, sock, address)
  self._conn_handler = ConnectionHandler(self) # XXX

上面的代碼就會產(chǎn)生交叉引用, 交叉引用會讓解釋器困惑, 從而之后只能靠2代和3代回收, 這個過程可能會很慢.

解決這種問題的方法就是使用 弱引用

import weakref

class ConnectionHandler(object):
 def __init__(self, connection):
  self._conn = connection


class Connection(object):
 def __init__(self, sock, address)
  self._conn_handler = ConnectionHandler(weakref.proxy(self)) # XXX

相關(guān)文章

  • 使用BeeWare實現(xiàn)iOS調(diào)用Python方式

    使用BeeWare實現(xiàn)iOS調(diào)用Python方式

    這篇文章主要介紹了使用BeeWare實現(xiàn)iOS調(diào)用Python方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • 解決Django migrate不能發(fā)現(xiàn)app.models的表問題

    解決Django migrate不能發(fā)現(xiàn)app.models的表問題

    今天小編就為大家分享一篇解決Django migrate不能發(fā)現(xiàn)app.models的表問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-08-08
  • python常用數(shù)據(jù)結(jié)構(gòu)字典梳理

    python常用數(shù)據(jù)結(jié)構(gòu)字典梳理

    這篇文章主要介紹了python常用數(shù)據(jù)結(jié)構(gòu)字典梳理,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-08-08
  • python怎么刪除緩存文件

    python怎么刪除緩存文件

    在本篇文章里小編給大家整理的是一篇關(guān)于python刪除緩存文件方法,需要的朋友們可以學習下。
    2020-07-07
  • python爬蟲中PhantomJS加載頁面的實例方法

    python爬蟲中PhantomJS加載頁面的實例方法

    在本篇文章里小編給大家整理了關(guān)于python爬蟲中PhantomJS加載頁面的實例方法,有需要的朋友們可以參考下。
    2020-11-11
  • Python Flask框架使用介紹

    Python Flask框架使用介紹

    今天來給大家說一個Python的輕量級web開發(fā)框架——Flask,為什么要推薦它呢?當然是因為它夠輕量級了,開發(fā)迅速是它的特點,當然它也有缺點,不過這里不說,因為既用它又說它差感覺不好
    2022-08-08
  • python文件夾分區(qū)的實現(xiàn)方法實例

    python文件夾分區(qū)的實現(xiàn)方法實例

    這篇文章主要給大家介紹了關(guān)于python文件夾分區(qū)的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-04-04
  • 淺談Python 列表字典賦值的陷阱

    淺談Python 列表字典賦值的陷阱

    今天小編就為大家分享一篇淺談Python 列表字典賦值的陷阱,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-01-01
  • Python?threading和Thread模塊及線程的實現(xiàn)

    Python?threading和Thread模塊及線程的實現(xiàn)

    這篇文章主要介紹了Python?threading和Thread模塊及線程的實現(xiàn),Python通過兩個標準庫thread和threading提供對線程的支持,threading對thread進行了封裝,具體實現(xiàn)介紹需要的朋友可以參考一下下面文章內(nèi)容
    2022-06-06
  • Flask框架學習筆記(一)安裝篇(windows安裝與centos安裝)

    Flask框架學習筆記(一)安裝篇(windows安裝與centos安裝)

    Flask是一個輕量級的Web應(yīng)用框架, 使用Python編寫。Flask也被稱為 “microframework” ,因為它使用簡單的核心,用 extension 增加其他功能。
    2014-06-06

最新評論