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

一文解密Python中的垃圾回收

 更新時間:2023年09月19日 11:35:47   作者:郝同學的測開筆記  
我們知道,python?是一種高級編程語言,它提供了自動內存管理的功能,即垃圾回收機制,所以本文就來聊聊python的垃圾回收機制是如何實現的以及具體是使用,感興趣的可以了解下

前言

我們知道,python 是一種高級編程語言,它提供了自動內存管理的功能,即垃圾回收機制。垃圾回收機制是一種自動管理內存的技術,它可以幫助開發(fā)者在編寫代碼時不必關注內存的分配和釋放,從而提高開發(fā)效率。好奇的同學會問了,python的垃圾回收機制到底是如何實現的呢?帶著疑問,我們一起進行探索。

為啥需要垃圾回收

  • 內存泄漏:在程序運行過程中,如果開發(fā)者沒有正確地釋放不再使用的內存,就會導致內存泄漏。內存泄漏會導致程序占用的內存越來越多,最終可能導致程序崩潰或者系統(tǒng)變得非常緩慢。垃圾回收機制可以自動檢測和回收不再使用的內存,避免內存泄漏的問題。
  • 簡化內存管理:在一些低級編程語言中,開發(fā)者需要手動分配和釋放內存,這樣容易出現內存泄漏和內存溢出的問題。而垃圾回收機制可以自動管理內存,開發(fā)者不需要關注內存的分配和釋放,從而提高開發(fā)效率。

總之,垃圾回收的存在是為了解決內存泄漏和簡化內存管理的問題。它可以自動檢測和回收不再使用的內存,避免內存泄漏,并提高開發(fā)效率。在高級編程語言中,垃圾回收是一項非常重要的功能。

怎么實現的呢

Python 的垃圾回收機制主要通過引用計數和循環(huán)引用檢測來實現。

引用計數

引用計數是一種簡單而高效的垃圾回收算法,它通過記錄每個對象的引用數量來判斷對象是否仍然被使用。當一個對象的引用計數為0時,說明該對象已經不再被使用,可以被回收。接下來,我們利用sys.getrefcount()查看變量的引用次數,這樣你一定會清晰很多。

案例一

import sys
?
a = []
?
print(sys.getrefcount(a)) # 2
?
def func(a):
 ? ?print(sys.getrefcount(a)) # 4
?
func(a)
?
print(sys.getrefcount(a)) # 2
?
  • 第一個print會輸出2,有2次引用,一次來自 a,一次來自 getrefcount
  • 第二個print會輸出4,有4次引用,一次來自a,一次來自python 的函數調用棧,一次來自函數參數,一次來自 getrefcount
  • 第三個print會輸出2,有2次引用,一次來自a,一次來自 getrefcount

強調一點:在函數調用發(fā)生時,會產生額外的2次引用,一次來自函數棧,一次來自函數參數

案例二

我們在舉個例子,加深理解

import sys
?
a = []
?
print(sys.getrefcount(a)) # 2
?
b = a
?
print(sys.getrefcount(a)) # 3
?
c = b
d = b
e = c
f = e
g = d
?
print(sys.getrefcount(a)) # 8
?

可以看到a、b、c、d、e、f、g 這些變量全部指代的是同一個對象,這個對象被引用8次,所以最終輸出8

案例三

我們看看,未回收和回收后內存的變化。

import os
import psutil
?
?
def show_memory_info(hint):
 ? ?pid = os.getpid()
 ? ?p = psutil.Process(pid)
?
 ? ?info = p.memory_full_info()
 ? ?memory = info.uss / 1024. / 1024
 ? ?print('{} memory used: {} MB'.format(hint, memory))
def func():
 ? ?show_memory_info('initial')
 ? ?a = [i for i in range(10000000)]
 ? ?show_memory_info('after a created')
?
func()
show_memory_info('finished')

我們定義了一個函數show_memory_info用來打印當前python程序占用的內存大小,定義了一個函數func()來創(chuàng)建變量a,在創(chuàng)建變量a之前打印占用內存,最后在函數func()調用銷毀后,再次打印內存占用。在看過案例一之后,相信你一定知道,函數內部聲明的列表 a 是局部變量,在函數返回后,局部變量的引用會注銷掉;此時,列表 a 所指代對象的引用數為 0,Python 便會執(zhí)行垃圾回收。我們看看執(zhí)行結果是不是這樣:

initial memory used: 30.75 MB
after a created memory used: 415.6328125 MB
finished memory used: 30.98828125 MB

可以看到確實如此。

那我們如果將變量聲明為全局變量,這樣函數銷毀后,列表的引用計數還存在,內存應該還是很大。測試一下:

def func():
 ? ?show_memory_info('initial')
 ? ?global a
 ? ?a = [i for i in range(10000000)]
 ? ?show_memory_info('after a created')

執(zhí)行結果如下:

initial memory used: 30.25390625 MB
after a created memory used: 415.38671875 MB
finished memory used: 415.38671875 MB

可以看到結果是滿足預期的。

那如果我們將func()函數生成的列表返回return a,然后調用函數并賦值給一個變量,此時列表引用也會存在,內存不會釋放。測試一下

def func():
 ? ?show_memory_info('initial')
 ? ?a = [i for i in range(10000000)]
 ? ?show_memory_info('after a created')
 ? ?return a
?
f = func()

執(zhí)行結果如下:

initial memory used: 30.1875 MB
after a created memory used: 415.0703125 MB
finished memory used: 415.0703125 MB

可以看到,確實還有大量內存被占用。

到這里,應該對引用計數釋放內存有一個清晰的認識了吧,現在,有人會問,我確實在某種場景下,需要手動釋放內存該怎么辦呢?當然python也是支持的,還是上面定義全局變量a的例子,我們只需要最后執(zhí)行del a,刪除對象的引用,然后強制調用gc.collect(),即可手動啟動垃圾回收。

循環(huán)引用

在上面案例三中,我們提到局部變量,在函數返回后,局部變量的引用會注銷掉??聪旅孢@段例子:

def func():
 ? ?show_memory_info('initial')
 ? ?a = [i for i in range(10000000)]
 ? ?b = [i for i in range(10000000)]
 ? ?show_memory_info('after a, b created')
 ? ?a.append(b)
 ? ?b.append(a)
func()
show_memory_info('finished')

按照我們上面學習的,a和b都是局部變量,函數返回后,應該引用計數會變?yōu)?,內存會釋放,我們測試一下:

執(zhí)行結果如下:

initial memory used: 30.80078125 MB
after a, b created memory used: 801.99609375 MB
finished memory used: 801.99609375 MB

可以看到內存并沒有釋放,說明ab的引用計數應該不為0。為啥出現這種情況呢?就是因為相互引用。那這種情況怎么解決呢?引用計數最后一部分提到,可以強制調用gc.collect()

什么是循環(huán)引用

循環(huán)引用是指兩個或多個對象之間相互引用,形成一個環(huán)狀結構。這種情況下,引用計數算法無法正確判斷對象是否仍然被使用,因為它們的引用計數永遠不會變?yōu)?。為了解決循環(huán)引用的問題,Python 引入了垃圾回收器,它使用了一種稱為標記-清除的算法。

標記-清除算法分為兩個階段:標記階段和清除階段。在標記階段,垃圾回收器會從根對象開始遍歷所有可達對象,并將它們標記為活動對象。而在清除階段,垃圾回收器會遍歷整個堆內存,將未標記的對象進行回收。

除了引用計數和標記-清除算法,Python 還使用了分代回收的策略。分代回收是一種基于對象存活時間的優(yōu)化策略,它將對象分為不同的代,每個代有不同的回收頻率。一般來說,新創(chuàng)建的對象會被分配到第0代,而經過一次垃圾回收后仍然存活的對象會被提升到下一代。這樣可以減少垃圾回收的頻率,提高性能。

如何調試內存泄漏

這里推薦objgraph,是一個可視化引用關系的包。

import objgraph
?
a = [1, 2, 3]
b = [4, 5, 6]
?
a.append(b)
b.append(a)
?
objgraph.show_refs([a])

這里通過show_refs()可以生成清晰的引用關系圖。

更多用法,可以參考文檔

最后

Python 的垃圾回收機制是一種自動管理內存的技術,它通過引用計數和循環(huán)引用檢測來判斷對象是否仍然被使用,并使用標記-清除算法進行回收。此外,還采用了分代回收的策略來優(yōu)化性能。了解這些垃圾回收機制的工作原理對于編寫高效的 Python 代碼非常重要。

以上就是一文解密Python中的垃圾回收的詳細內容,更多關于Python垃圾回收的資料請關注腳本之家其它相關文章!

相關文章

  • Python unittest基本使用方法代碼實例

    Python unittest基本使用方法代碼實例

    這篇文章主要介紹了Python unittest基本使用方法代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-06-06
  • python 連接sqlite及簡單操作

    python 連接sqlite及簡單操作

    本文通過實例代碼給大家介紹了python 連接sqlite及簡單操作,非常不錯,具有參考借鑒價值,需要的朋友參考下吧
    2017-06-06
  • Django中反向生成models.py的實例講解

    Django中反向生成models.py的實例講解

    今天小編就為大家分享一篇Django中反向生成models.py的實例講解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-05-05
  • python單線程實現多個定時器示例

    python單線程實現多個定時器示例

    這篇文章主要介紹了python單線程實現多個定時器示例,需要的朋友可以參考下
    2014-03-03
  • python-itchat 統(tǒng)計微信群、好友數量,及原始消息數據的實例

    python-itchat 統(tǒng)計微信群、好友數量,及原始消息數據的實例

    今天小編就為大家分享一篇python-itchat 統(tǒng)計微信群、好友數量,及原始消息數據的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-02-02
  • 詳解django三種文件下載方式

    詳解django三種文件下載方式

    這篇文章主要介紹了詳解django三種文件下載方式,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-04-04
  • 解決pycharm運行程序出現卡住scanning files to index索引的問題

    解決pycharm運行程序出現卡住scanning files to index索引的問題

    今天小編就為大家分享一篇解決pycharm運行程序出現卡住scanning files to index索引的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-06-06
  • pytorch 中pad函數toch.nn.functional.pad()的用法

    pytorch 中pad函數toch.nn.functional.pad()的用法

    今天小編就為大家分享一篇pytorch 中pad函數toch.nn.functional.pad()的用法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-01-01
  • python的mysql數據庫建立表與插入數據操作示例

    python的mysql數據庫建立表與插入數據操作示例

    這篇文章主要介紹了python的mysql數據庫建立表與插入數據操作,結合實例形式分析了python操作mysql數據庫建立表與插入數據相關實現技巧,需要的朋友可以參考下
    2019-09-09
  • Pandas中`ValueError: cannot reindex from a duplicate axis`錯誤分析及解決辦法

    Pandas中`ValueError: cannot reindex from 

    在Pandas中,ValueError: cannot reindex from a duplicate axis錯誤通常發(fā)生在嘗試對包含重復索引的DataFrame或Series進行重新索引(reindex)時,所以本文介紹了Pandas中`ValueError: cannot reindex from a duplicate axis`錯誤分析及解決辦法,需要的朋友可以參考下
    2024-07-07

最新評論

涞水县| 长海县| 如东县| 河间市| 昌邑市| 杂多县| 茂名市| 临夏市| 昭觉县| 井冈山市| 张掖市| 井研县| 綦江县| 郴州市| 平陆县| 伊川县| 绥中县| 通海县| 德令哈市| 郓城县| 理塘县| 新宁县| 石家庄市| 海林市| 淮南市| 曲周县| 沅江市| 彭水| 晴隆县| 柳林县| 金坛市| 南木林县| 礼泉县| 河西区| 东光县| 正安县| 冷水江市| 柯坪县| 永城市| 黔江区| 海宁市|