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

Python萬字深入內(nèi)存管理講解

 更新時間:2022年07月21日 15:05:22   作者:Flyme?awei  
內(nèi)存管理是指在程序的運行過程中,分配內(nèi)容和回收內(nèi)存的過程。如果只分配,不回收,電腦上那點內(nèi)存很快就被用光。幸運的是,Python和Java等高級語言會自動管理內(nèi)存的分配和回收

Python內(nèi)存管理

一、對象池

1.小整數(shù)池

系統(tǒng)默認創(chuàng)建好的,等著你使用

概述:

整數(shù)在程序中的使用非常廣泛,Python為了優(yōu)化速度,使用了小整數(shù)對象池,避免為整數(shù)頻繁申請和銷毀內(nèi)存空間。

Python 對小整數(shù)的定義是 [-5, 256] ,這些整數(shù)對象是提前建立好的,不會被垃圾回收。

在一個 Python 的程序中,無論這個整數(shù)處于LEGB(局部變量,閉包,全局,內(nèi)建模塊)中的哪個位置,所有位于這個范圍內(nèi)的整數(shù)使用的都是同一個對象。

# 交互式環(huán)境下:
>>> a = 100
>>> b = 100
>>> id(a)
140720433537792
>>> id(b)
140720433537792
>>> a is b
True
>>> 

我們可以看出a,b指向同一個內(nèi)存地址。

2.大整數(shù)池

大整數(shù)池:默認創(chuàng)建出來,池內(nèi)為空的,創(chuàng)建一個就會往池中存儲一個

# python交互式環(huán)境
>>> a = 257
>>> b = 257
>>> id(a)
2085029722896
>>> id(b)
2085029722960
>>> a is b
False
>>> 

a , b 不是指向同一個內(nèi)存地址。

python中對大于256的整數(shù),會重新分配對象空間地址保存對象。

3.inter機制(短字符串池)

每個單詞(字符串),不夾雜空格或者其他符號,默認開啟intern機制,共享內(nèi)存,靠引用計數(shù)決定是否銷毀。

>>> s1 = 'hello'
>>> s2 = 'hello'
>>> id(s1)
2178093449264
>>> id(s2)
2178093449264
>>> s1 is s2
True
>>> 

字符串s1和s2中沒有空格時,可以看出,這里的s1與s2指向同一個內(nèi)存地址。

當(dāng)我們在he和llo之間加一個空格

>>> s1 = 'he llo'
>>> s2 = 'he llo'
>>> id(s1)
2278732636592
>>> id(s2)
2278732636528
>>> s1 is s2
False
>>> 

這時的字符串s1和s2就沒有指向同一個內(nèi)存地址。

對于字符串來說,如果不包含空格的字符串,則不會重新分配對象空間,對于包含空格的字符串則會重新分配對象空間。

二、垃圾回收

概述:

python采用的是引用計數(shù)機制為主,隔代回收和標(biāo)記清除機制為輔的策略

概述:
現(xiàn)在的高級語言如java,c\# 等,都采用了垃圾收集機制,而不再是c,c++里用戶自己管理維護內(nèi)存的方式。

自己管理 內(nèi)存極其自由, 可以任意申請內(nèi)存,但如同一把雙刃劍,為大量內(nèi)存泄露,懸空指針等bug埋下隱患。 

python里也同java一樣采用了垃圾收集機制,不過不一樣的是: 
python采用的是引用計數(shù)機制為主,隔代回收機制為輔的策略

2.1.引用計數(shù)

在Python中,每個對象都有指向該對象的引用總數(shù)---引用計數(shù) 

查看對象的引用計數(shù):sys.getrefcount() 

注意:
    當(dāng)使用某個引用作為參數(shù),傳遞給getrefcount()時,參數(shù)實際上創(chuàng)建了一個臨時的引用。
    因此, getrefcount()所得到的結(jié)果,會比期望的多1。

2.1.1 引用計數(shù)增加

a、對象被創(chuàng)建

b、另外變量也指向當(dāng)前對象

c、作為容器對象的一個元素

d、作為參數(shù)提供給函數(shù):test(x)

2.1.2 引用計數(shù)減少

a、變量被顯式的銷毀

b、對象的另外一個變量重新賦值

c、從容器中移除

d、函數(shù)被執(zhí)行完畢

看代碼:

# -*- coding: utf-8 -*-
import sys
class Test(object):
    def __init__(self):
        print('當(dāng)前對象已經(jīng)被創(chuàng)建,占用的內(nèi)存地址為:%s' % hex(id(self)))
a = Test()
print('當(dāng)前對象的引用計數(shù)為:%s' % sys.getrefcount(a))  # 2
b = a
print('當(dāng)前對象的引用計數(shù)為:%s' % sys.getrefcount(a))  # 3
list1 = []
list1.append(a)
print('當(dāng)前對象的引用計數(shù)為:%s' % sys.getrefcount(a))  # 4
del b
print('當(dāng)前對象的引用計數(shù)為:%s' % sys.getrefcount(a))  # 3
list1.remove(a)
print('當(dāng)前對象的引用計數(shù)為:%s' % sys.getrefcount(a))  # 2
del a
print('當(dāng)前對象的引用計數(shù)為:%s' % sys.getrefcount(a))  # 報錯
'''
Traceback (most recent call last):
  File "E:/Python Project/Python 高級編程/內(nèi)存管理/垃圾收集.py", line 30, in <module>
    print('當(dāng)前對象的引用計數(shù)為:%s' % sys.getrefcount(a))
NameError: name 'a' is not defined
'''

當(dāng)Python的某個對象的引用計數(shù)降為0時,說明沒有任何引用指向該對象,該對象就成為要被回收的垃圾。比如某個新建對象,被分配給某個引用,對象的引用計數(shù)變?yōu)?。如 為0,那么該對象就可以被垃圾回收。

2.2.標(biāo)記清除

標(biāo)記清除(Mark—Sweep)算法是一種基于追蹤回收(tracing GC)技術(shù)實現(xiàn)的垃圾回收算法。

它分為兩個階段:

第一階段是標(biāo)記階段,GC會把所有的活動對象打上標(biāo)記

第二階段是把那些沒有標(biāo)記的對象非活動對象進行回收。

對象之間通過引用(指針)連在一起,構(gòu)成一個有向圖,對象構(gòu)成這個有向圖的節(jié)點,而引用關(guān)系構(gòu)成這個有向圖的邊。從根對象(root object)出發(fā),沿著有向邊遍歷對象,可達的(reachable)對象標(biāo)記為活動對象,不可達的對象就是要被清除的非活動對象。根對象就是全局變量、調(diào)用棧、寄存器。

>

在上圖中,可以從程序變量直接訪問塊1,并且可以間接訪問塊2和3。程序無法訪問塊4和5。第一步將標(biāo)記塊1,并記住塊2和3以供稍后處理。第二步將標(biāo)記塊2,第三步將標(biāo)記塊3,但不記得塊2,因為它已被標(biāo)記。掃描階段將忽略塊1,2和3,因為它們已被標(biāo)記,但會回收塊4和5。

標(biāo)記清除算法作為Python的輔助垃圾收集技術(shù),主要處理的是一些容器對象,比如list、dict、tuple等,因為對于字符串、數(shù)值對象是不可能造成循環(huán)引用問題。Python使用一個雙向鏈表將這些容器對象組織起來。不過,這種簡單粗暴的標(biāo)記清除算法也有明顯的缺點:清除非活動的對象前它必須順序掃描整個堆內(nèi)存,哪怕只剩下小部分活動對象也要掃描所有對象。

2.3.分代回收

因為, 標(biāo)記和清除的過程效率不高。清除非活動的對象前它必須順序掃描整個堆內(nèi)存,哪怕只剩下小部分活動對象也要掃描所有對象。還有一個問題就是:什么時候掃描去檢測循環(huán)引用?

為了解決上述的問題,python又引入了分代回收。分代回收解決了標(biāo)記清楚時什么時候掃描的問題,并且將掃描的對象分成了3級,以及降低掃描的工作量,提高效率。

  • 0代: 0代中對象個數(shù)達到700個,掃描一次。
  • 1代: 0代掃描10次,則1代掃描1次。
  • 2代: 1代掃描10次,則2代掃描1次。

隔代回收是用來解決交叉引用(循環(huán)引用),并增加數(shù)據(jù)回收的效率. 原理:通過對象存在的時間不同,采用不同的算法來 回收垃圾.

形象的比喻, 三個鏈表,零代鏈表上的對象(新創(chuàng)建的對象都加入到零代鏈表),引用數(shù)都是一,每增加一個指針,引用加一,隨后 python會檢測列表中的互相引用的對象,根據(jù)規(guī)則減掉其引用計數(shù).

GC算法對鏈表一的引用減一,引用為0的,清除,不為0的到鏈表二,鏈表二也執(zhí)行GC算法,鏈表三一樣. 存在時間越長的 數(shù)據(jù),越是有用的數(shù)據(jù)

2.3.1 分代回收觸發(fā)時機?(GC閾值)

隨著你的程序運行,Python解釋器保持對新創(chuàng)建的對象,以及因為引用計數(shù)為零而被釋放掉的對象的追蹤。

從理論上說,這兩個值應(yīng)該保持一致,因為程序新建的每個對象都應(yīng)該最終被釋放掉。當(dāng)然,事實并非如此。因為循環(huán) 引用的原因,從而被分配對象的計數(shù)值與被釋放對象的計數(shù)值之間的差異在逐漸增長。一旦這個差異累計超過某個閾 值,則Python的收集機制就啟動了,并且觸發(fā)上邊所說到的零代算法,釋放“浮動的垃圾”,并且將剩下的對象移動到 一代列表。

隨著時間的推移,程序所使用的對象逐漸從零代列表移動到一代列表。而Python對于一代列表中對象的處理遵循同樣的 方法,一旦被分配計數(shù)值 與被釋放計數(shù)值累計到達一定閾值,Python會將剩下的活躍對象移動到二代列表。

通過這種方法,你的代碼所長期使用 的對象,那些你的代碼持續(xù)訪問的活躍對象,會從零代鏈表轉(zhuǎn)移到一代再轉(zhuǎn)移到二代。

通過不同的閾值設(shè)置,Python可 以在不同的時間間隔處理這些對象。

Python處理零代最為頻繁,其次是一代然后才是二代。

2.3.2 查看引用計數(shù)(gc模塊的使用)

# 引入gc模塊
import gc 
# 常用函數(shù): 
gc.get_count() 
# 獲取當(dāng)前自動執(zhí)行垃圾回收的計數(shù)器,返回一個長度為3的列表
gc.get_threshold() 
# 獲取gc模塊中自動執(zhí)行垃圾回收的頻率 
gc.set_threshold(threshold0[,threshold1,threshold2]) 
# 設(shè)置自動執(zhí)行垃圾回收的頻率 
gc.disable() 
# python3默認開啟gc機制,可以使用該方法手動關(guān)閉gc機制 
gc.collect() 
# 手動調(diào)用垃圾回收機制回收垃圾

內(nèi)存管理是使用計算機必不可少的一部分,無論好壞,Python幾乎會在后臺處理一切內(nèi)存管理的問題。Python抽象出許多使用計算機的嚴格細節(jié),這讓我們在更高層次進行開發(fā),而不用擔(dān)心所有字節(jié)的存儲方式和位置。

# -*- coding: utf-8 -*-
import gc
import sys
import time
class Test(object):
    def __init__(self):
        print('當(dāng)前對象已經(jīng)被創(chuàng)建,占用的內(nèi)存地址為:%s' % hex(id(self)))
    def __del__(self):
        print('當(dāng)前對象馬上被系統(tǒng)GC回收')
# gc.disable()  # 不啟用GC,在python3中默認啟用
while True:
    a = Test()
    b = Test()
    a.pro = b  # a 和 b之間相互引用
    b.pro = a
    del a
    del b
    print(gc.get_threshold())  # 打印隔代回收的閾值
    print(gc.get_count())  # 打印GC需要回收的對象
    time.sleep(0.2)  # 休眠0.2秒方便查看

終端輸出:

三、怎么優(yōu)化內(nèi)存管理

1.手動垃圾回收

先調(diào)用del a ; 再調(diào)用gc.collect()即可手動啟動GC

2.調(diào)高垃圾回收閾值

gc.set_threshold 設(shè)置垃圾回收閾值(收集頻率)。

將 threshold 設(shè)為零會禁用回收。

3.避免循環(huán)引用

四、總結(jié)

python采用的是引用計數(shù)機制為主,標(biāo)記-清除和分代回收(隔代回收)兩種機制為輔的策略

到此這篇關(guān)于Python萬字深入內(nèi)存管理講解的文章就介紹到這了,更多相關(guān)Python內(nèi)存管理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Python配置mysql的教程(推薦)

    Python配置mysql的教程(推薦)

    下面小編就為大家?guī)硪黄狿ython配置mysql的教程(推薦)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-10-10
  • Python項目管理工具Poetry使用示例詳解

    Python項目管理工具Poetry使用示例詳解

    這篇文章主要為大家介紹了Python項目管理工具Poetry使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-09-09
  • python繪制玫瑰的實現(xiàn)代碼

    python繪制玫瑰的實現(xiàn)代碼

    這篇文章主要介紹了python繪制玫瑰的實現(xiàn)代碼,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-03-03
  • 使用PyOpenGL繪制三維坐標(biāo)系實例

    使用PyOpenGL繪制三維坐標(biāo)系實例

    今天小編就為大家分享一篇使用PyOpenGL繪制三維坐標(biāo)系實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-12-12
  • 一篇文章帶你詳細了解python中一些好用的庫

    一篇文章帶你詳細了解python中一些好用的庫

    這篇文章主要推薦了一些好用的Python庫,都有這不錯的群眾基礎(chǔ),非常好用,也都很實用,推薦給大家,希望能夠給你帶來幫助
    2021-09-09
  • python操作攝像頭截圖實現(xiàn)遠程監(jiān)控的例子

    python操作攝像頭截圖實現(xiàn)遠程監(jiān)控的例子

    這篇文章主要介紹了python操作攝像頭截圖實現(xiàn)遠程監(jiān)控的例子,例子中包含了控制攝像頭、寫入Windows注冊表方法等,需要的朋友可以參考下
    2014-03-03
  • 使用selenium模擬動態(tài)登錄百度頁面的實現(xiàn)

    使用selenium模擬動態(tài)登錄百度頁面的實現(xiàn)

    本文主要介紹了使用selenium模擬動態(tài)登錄百度頁面,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • python自動化發(fā)送郵件實例講解

    python自動化發(fā)送郵件實例講解

    在本篇文章里小編給大家分享了一篇關(guān)于python自動化發(fā)送郵件實例講解內(nèi)容,有興趣的朋友們可以學(xué)習(xí)參考下。
    2021-01-01
  • Python實現(xiàn)博客快速備份的腳本分享

    Python實現(xiàn)博客快速備份的腳本分享

    本文針對博客園實現(xiàn)了一個自動備份腳本,可以快速將自己的文章備份成Markdown格式的獨立文件,備份后的md文件可以直接放入到hexo博客中,感興趣的可以了解一下
    2022-09-09
  • 使用pickle存儲數(shù)據(jù)dump 和 load實例講解

    使用pickle存儲數(shù)據(jù)dump 和 load實例講解

    今天小編就為大家分享一篇使用pickle存儲數(shù)據(jù)dump 和 load實例講解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-12-12

最新評論

沙雅县| 正阳县| 衡山县| 集贤县| 格尔木市| 阜南县| 商丘市| 上犹县| 福州市| 罗甸县| 道孚县| 台山市| 阜南县| 高平市| 青铜峡市| 三门县| 鄂托克前旗| 平泉县| 弥渡县| 永顺县| 白城市| 集安市| 永寿县| 荣成市| 花垣县| 富锦市| 大宁县| 姚安县| 青冈县| 万宁市| 敦化市| 西贡区| 德兴市| 五家渠市| 兖州市| 温宿县| 浦东新区| 特克斯县| 偃师市| 容城县| 陕西省|