<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
系統預設建立好的,等著你使用
概述:
整數在程式中的使用非常廣泛,Python為了優化速度,使用了小整數物件池,避免為整數頻繁申請和銷燬記憶體空間。
Python 對小整數的定義是 [-5, 256] ,這些整數物件是提前建立好的,不會被垃圾回收。
在一個 Python 的程式中,無論這個整數處於LEGB(區域性變數,閉包,全域性,內建模組)中的哪個位置,所有位於這個範圍內的整數使用的都是同一個物件。
# 互動式環境下: >>> a = 100 >>> b = 100 >>> id(a) 140720433537792 >>> id(b) 140720433537792 >>> a is b True >>>
我們可以看出a,b指向同一個記憶體地址。
大整數池:預設建立出來,池內為空的,建立一個就會往池中儲存一個
# python互動式環境 >>> a = 257 >>> b = 257 >>> id(a) 2085029722896 >>> id(b) 2085029722960 >>> a is b False >>>
a , b 不是指向同一個記憶體地址。
python中對大於256的整數,會重新分配物件空間地址儲存物件。
每個單詞(字串),不夾雜空格或者其他符號,預設開啟intern機制,共用記憶體,靠參照計數決定是否銷燬。
>>> s1 = 'hello' >>> s2 = 'hello' >>> id(s1) 2178093449264 >>> id(s2) 2178093449264 >>> s1 is s2 True >>>
字串s1和s2中沒有空格時,可以看出,這裡的s1與s2指向同一個記憶體地址。
當我們在he和llo之間加一個空格
>>> s1 = 'he llo' >>> s2 = 'he llo' >>> id(s1) 2278732636592 >>> id(s2) 2278732636528 >>> s1 is s2 False >>>
這時的字串s1和s2就沒有指向同一個記憶體地址。
對於字串來說,如果不包含空格的字串,則不會重新分配物件空間,對於包含空格的字串則會重新分配物件空間。
概述:
python採用的是參照計數機制為主,隔代回收和標記清除機制為輔的策略
概述:
現在的高階語言如java,c# 等,都採用了垃圾收集機制,而不再是c,c++裡使用者自己管理維護記憶體的方式。
自己管理 記憶體極其自由, 可以任意申請記憶體,但如同一把雙刃劍,為大量記憶體洩露,懸空指標等bug埋下隱患。
python裡也同java一樣採用了垃圾收集機制,不過不一樣的是:
python採用的是參照計數機制為主,隔代回收機制為輔的策略
在Python中,每個物件都有指向該物件的參照總數---參照計數
檢視物件的參照計數:sys.getrefcount()
注意:
當使用某個參照作為引數,傳遞給getrefcount()時,引數實際上建立了一個臨時的參照。
因此, getrefcount()所得到的結果,會比期望的多1。
a、物件被建立
b、另外變數也指向當前物件
c、作為容器物件的一個元素
d、作為引數提供給函數:test(x)
a、變數被顯式的銷燬
b、物件的另外一個變數重新賦值
c、從容器中移除
d、函數被執行完畢
看程式碼:
# -*- coding: utf-8 -*- import sys class Test(object): def __init__(self): print('當前物件已經被建立,佔用的記憶體地址為:%s' % hex(id(self))) a = Test() print('當前物件的參照計數為:%s' % sys.getrefcount(a)) # 2 b = a print('當前物件的參照計數為:%s' % sys.getrefcount(a)) # 3 list1 = [] list1.append(a) print('當前物件的參照計數為:%s' % sys.getrefcount(a)) # 4 del b print('當前物件的參照計數為:%s' % sys.getrefcount(a)) # 3 list1.remove(a) print('當前物件的參照計數為:%s' % sys.getrefcount(a)) # 2 del a print('當前物件的參照計數為:%s' % sys.getrefcount(a)) # 報錯 ''' Traceback (most recent call last): File "E:/Python Project/Python 高階程式設計/記憶體管理/垃圾收集.py", line 30, in <module> print('當前物件的參照計數為:%s' % sys.getrefcount(a)) NameError: name 'a' is not defined '''
當Python的某個物件的參照計數降為0時,說明沒有任何參照指向該物件,該物件就成為要被回收的垃圾。比如某個新建物件,被分配給某個參照,物件的參照計數變為1。如 為0,那麼該物件就可以被垃圾回收。
標記清除(Mark—Sweep)演演算法是一種基於追蹤回收(tracing GC)技術實現的垃圾回收演演算法。
它分為兩個階段:
第一階段是標記階段,GC會把所有的活動物件打上標記
第二階段是把那些沒有標記的物件非活動物件進行回收。
物件之間通過參照(指標)連在一起,構成一個有向圖,物件構成這個有向圖的節點,而參照關係構成這個有向圖的邊。從根物件(root object)出發,沿著有向邊遍歷物件,可達的(reachable)物件標記為活動物件,不可達的物件就是要被清除的非活動物件。根物件就是全域性變數、呼叫棧、暫存器。
>
在上圖中,可以從程式變數直接存取塊1,並且可以間接存取塊2和3。程式無法存取塊4和5。第一步將標記塊1,並記住塊2和3以供稍後處理。第二步將標記塊2,第三步將標記塊3,但不記得塊2,因為它已被標記。掃描階段將忽略塊1,2和3,因為它們已被標記,但會回收塊4和5。
標記清除演演算法作為Python的輔助垃圾收集技術,主要處理的是一些容器物件,比如list、dict、tuple等,因為對於字串、數值物件是不可能造成迴圈參照問題。Python使用一個雙向連結串列將這些容器物件組織起來。不過,這種簡單粗暴的標記清除演演算法也有明顯的缺點:清除非活動的物件前它必須順序掃描整個堆記憶體,哪怕只剩下小部分活動物件也要掃描所有物件。
因為, 標記和清除的過程效率不高。清除非活動的物件前它必須順序掃描整個堆記憶體,哪怕只剩下小部分活動物件也要掃描所有物件。還有一個問題就是:什麼時候掃描去檢測迴圈參照?
為了解決上述的問題,python又引入了分代回收。分代回收解決了標記清楚時什麼時候掃描的問題,並且將掃描的物件分成了3級,以及降低掃描的工作量,提高效率。
隔代回收是用來解決交叉參照(迴圈參照),並增加資料回收的效率. 原理:通過物件存在的時間不同,採用不同的演演算法來 回收垃圾.
形象的比喻, 三個連結串列,零代連結串列上的物件(新建立的物件都加入到零代連結串列),參照數都是一,每增加一個指標,參照加一,隨後 python會檢測列表中的互相參照的物件,根據規則減掉其參照計數.
GC演演算法對連結串列一的參照減一,參照為0的,清除,不為0的到連結串列二,連結串列二也執行GC演演算法,連結串列三一樣. 存在時間越長的 資料,越是有用的資料
隨著你的程式執行,Python直譯器保持對新建立的物件,以及因為參照計數為零而被釋放掉的物件的追蹤。
從理論上說,這兩個值應該保持一致,因為程式新建的每個物件都應該最終被釋放掉。當然,事實並非如此。因為迴圈 參照的原因,從而被分配物件的計數值與被釋放物件的計數值之間的差異在逐漸增長。一旦這個差異累計超過某個閾 值,則Python的收集機制就啟動了,並且觸發上邊所說到的零代演演算法,釋放“浮動的垃圾”,並且將剩下的物件移動到 一代列表。
隨著時間的推移,程式所使用的物件逐漸從零代列表移動到一代列表。而Python對於一代列表中物件的處理遵循同樣的 方法,一旦被分配計數值 與被釋放計數值累計到達一定閾值,Python會將剩下的活躍物件移動到二代列表。
通過這種方法,你的程式碼所長期使用 的物件,那些你的程式碼持續存取的活躍物件,會從零代連結串列轉移到一代再轉移到二代。
通過不同的閾值設定,Python可 以在不同的時間間隔處理這些物件。
Python處理零代最為頻繁,其次是一代然後才是二代。
# 引入gc模組 import gc # 常用函數: gc.get_count() # 獲取當前自動執行垃圾回收的計數器,返回一個長度為3的列表 gc.get_threshold() # 獲取gc模組中自動執行垃圾回收的頻率 gc.set_threshold(threshold0[,threshold1,threshold2]) # 設定自動執行垃圾回收的頻率 gc.disable() # python3預設開啟gc機制,可以使用該方法手動關閉gc機制 gc.collect() # 手動呼叫垃圾回收機制回收垃圾
記憶體管理是使用計算機必不可少的一部分,無論好壞,Python幾乎會在後臺處理一切記憶體管理的問題。Python抽象出許多使用計算機的嚴格細節,這讓我們在更高層次進行開發,而不用擔心所有位元組的儲存方式和位置。
# -*- coding: utf-8 -*- import gc import sys import time class Test(object): def __init__(self): print('當前物件已經被建立,佔用的記憶體地址為:%s' % hex(id(self))) def __del__(self): print('當前物件馬上被系統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秒方便檢視
終端輸出:
先呼叫del a ; 再呼叫gc.collect()即可手動啟動GC
gc.set_threshold 設定垃圾回收閾值(收集頻率)。
將 threshold 設為零會禁用回收。
python採用的是參照計數機制為主,標記-清除和分代回收(隔代回收)兩種機制為輔的策略
到此這篇關於Python萬字深入記憶體管理講解的文章就介紹到這了,更多相關Python記憶體管理內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45