『壹』 python如何進行內存管理
Python中的變數並不直接存儲值,而是存儲了值的內存地址或者引用,假如為不同變數賦值為相同值,這個值在內存中只有一份,多個變數指向同一塊內存地址。
『貳』 如何釋放Python佔用的內存
python有引用計數進行垃圾回收配合內存池管理技術自動管理內存,一般不需要主動處理,可以使用del刪除引用,對象由自動垃圾回收機制釋放。
『叄』 Python里的垃圾回收機制是什麼意思,搞不懂
如果你用C++寫程序的話 有時候需要動態內存 就是在你需要的時候給你分配空間 但是如果回你忘記把它釋答放或者你把指向那塊內存的指針給搞丟了,那麼那塊內存就不能夠再使用。如果你的程序不斷的申請但又不釋放內存,那麼電腦內存的使用就越來越高。最後直接99% 程序崩潰電腦卡死
但是java就不會了 她回主動幫你釋放不用的內存 就是垃圾回收機制 但是這個回收時間 回收哪裡也是有講究的,這里就不細說了。
總之,java比其他語言比如c c++安全 但是相應的效率就沒有那麼高了
程序 就是個時間空間的交換游戲嘛!
『肆』 Python如何管理內存
Python中的內存管理是從三個方面來進行的,一對象的引用計數機制,二垃圾回收機制,三內存池機制
一、對象的引用計數機制
Python內部使用引用計數,來保持追蹤內存中的對象,所有對象都有引用計數。
引用計數增加的情況:
1,一個對象分配一個新名稱
2,將其放入一個容器中(如列表、元組或字典)
引用計數減少的情況:
1,使用del語句對對象別名顯示的銷毀
2,引用超出作用域或被重新賦值
sys.getrefcount( )函數可以獲得對象的當前引用計數
多數情況下,引用計數比你猜測得要大得多。對於不可變數據(如數字和字元串),解釋器會在程序的不同部分共享內存,以便節約內存。
二、垃圾回收
1,當一個對象的引用計數歸零時,它將被垃圾收集機制處理掉。
2,當兩個對象a和b相互引用時,del語句可以減少a和b的引用計數,並銷毀用於引用底層對象的名稱。然而由於每個對象都包含一個對其他對象的應用,因此引用計數不會歸零,對象也不會銷毀。(從而導致內存泄露)。為解決這一問題,解釋器會定期執行一個循環檢測器,搜索不可訪問對象的循環並刪除它們。
三、內存池機制
Python提供了對內存的垃圾收集機制,但是它將不用的內存放到內存池而不是返回給操作系統。
1,Pymalloc機制。為了加速Python的執行效率,Python引入了一個內存池機制,用於管理對小塊內存的申請和釋放。
2,Python中所有小於256個位元組的對象都使用pymalloc實現的分配器,而大的對象則使用系統的malloc。
3,對於Python對象,如整數,浮點數和List,都有其獨立的私有內存池,對象間不共享他們的內存池。也就是說如果你分配又釋放了大量的整數,用於緩存這些整數的內存就不能再分配給浮點數。
『伍』 Python垃圾回收機制是什麼樣的
Python垃圾回收機制是通過引用計數來管理的引用計數表示記錄這個對象被引用專的次數如果屬有新的引用指向對象,對象引用計數就加一,引用被銷毀時,對象引用計數減一,當用戶的引用計數為0時,該內存被釋放以上就是Python的垃圾回收機制了 ,在黑馬程序員看過一個視頻,有專門講解的,你可以去看看!謝謝你,如果你有這方面的問題的話,您可以隨時詢問我
『陸』 為什麼Python工程師很少像Java工程師那樣討論垃圾回收
面試題
1、Python是如何進行內存管理的?
Python的內存管理主要有三種機制:引用計數機制、垃圾回收機制和內存池機制。
a. 引用計數
當給一個對象分配一個新名稱或者將一個對象放入一個容器(列表、元組或字典)時,該對象的引用計數都會增加。
當使用del對對象顯示銷毀或者引用超出作用於或者被重新賦值時,該對象的引用計數就會減少。
可以使用sys.getrefcount()函數來獲取對象的當前引用計數。多數情況下,引用計數要比我們猜測的大的 多。對於不可變數據(數字和字元串),解釋器會在程序的不同部分共享內存,以便節約內存。
b. 垃圾回收
當一個對象的引用計數歸零時,它將被垃圾收集機制處理掉。
當
兩個對象a和b相互引用時,del語句可以減少a和b的引用計數,並銷毀用於引用底層對象的名稱。然而由於每個對象都包含一個對其他對象的應用,因此引用
計數不會歸零,對象也不會銷毀。(從而導致內存泄露)。為解決這一問題,解釋器會定期執行一個循環檢測器,搜索不可訪問對象的循環並刪除它們。
c. 內存池機制
Python提供了對內存的垃圾收集機制,但是它將不用的內存放到內存池而不是返回給操作系統。
1)Pymalloc機制。為了加速Python的執行效率,Python引入了一個內存池機制,用於管理對小塊內存的申請和釋放。
2)Python中所有小於256個位元組的對象都使用pymalloc實現的分配器,而大的對象則使用系統的 malloc。
3)對於Python對象,如整數,浮點數和List,都有其獨立的私有內存池,對象間不共享他們的內存池。也就是說如果你分配又釋放了大量的整數,用於緩存這些整數的內存就不能再分配給浮點數。
【Python環境】12道 Python面試題總結
2、什麼是lambda函數?它有什麼好處?
lambda 表達式,通常是在需要一個函數,但是又不想費神去命名一個函數的場合下使用,也就是指匿名函數
lambda函數:首要用途是指點短小的回調函數
lambda [arguments]: expression
>>> a=lambda x,y:x+y
>>> a(3,11)
3、Python裡面如何實現tuple和list的轉換?
直接使用tuple和list函數就行了,type()可以判斷對象的類型。
4、請寫出一段Python代碼實現刪除一個list裡面的重復元素。
這個地方用set可以實現。
5、Python裡面如何拷貝一個對象?(賦值,淺拷貝,深拷貝的區別)
賦值(=),就是創建了對象的一個新的引用,修改其中任意一個變數都會影響到另一個。
淺拷貝:創建一個新的對象,但它包含的是對原始對象中包含項的引用(如果用引用的方式修改其中一個對象,另外一個也會修改改變){1,完全切片方法;2,工廠函數,如list();3,模塊的()函數}
深拷貝:創建一個新的對象,並且遞歸的復制它所包含的對象(修改其中一個,另外一個不會改變){模塊的deep.deep()函數}
6、介紹一下except的用法和作用?
try…except…except…[else…][finally…]
執行try下的語句,如果引發異常,則執行過程會跳到except語句。對每個except分支順序嘗試執行,如果引發的異常與except中的異常組匹配,執行相應的語句。如果所有的except都不匹配,則異常會傳遞到下一個調用本代碼的最高層try代碼中。
try下的語句正常執行,則執行else塊代碼。如果發生異常,就不會執行
如果存在finally語句,最後總是會執行。
【Python環境】12道 Python面試題總結
7、Python裡面match()和search()的區別?
re模塊中match(pattern,string [,flags]),檢查string的開頭是否與pattern匹配。
re模塊中research(pattern,string [,flags]),在string搜索pattern的第一個匹配值。
>>> print(re.match(『super』, 『superstition』).span())
(0, 5)
>>> print(re.match(『super』, 『insuperable』))
None
>>> print(re.search(『super』, 『superstition』).span())
(0, 5)
>>> print(re.search(『super』, 『insuperable』).span())
(2, 7)
8、用Python匹配HTML tag的時候,<.*>和<.*?>有什麼區別?
術語叫貪婪匹配( <.*> )和非貪婪匹配( <.*?> )
例如:
test
<.*> :
test
<.*?> :
9、以下的代碼的輸出將是什麼? 說出你的答案並解釋
輸出:
使你困惑或是驚奇的是關於最後一行的輸出是 3 2 3 而不是 3 2 1。為什麼改變了 Parent.x 的值還會改變 Child2.x 的值,但是同時 Child1.x 值卻沒有改變?
這
個答案的關鍵是,在 Python
中,類變數在內部是作為字典處理的。如果一個變數的名字沒有在當前類的字典中發現,將搜索祖先類(比如父類)直到被引用的變數名被找到(如果這個被引用的
變數名既沒有在自己所在的類又沒有在祖先類中找到,會引發一個 AttributeError 異常 )。
因此,在父類中設置 x = 1 會使得類變數 X 在引用該類和其任何子類中的值為 1。這就是因為第一個 print 語句的輸出是 1 1 1。
隨後,如果任何它的子類重寫了該值(例如,我們執行語句 Child1.x = 2),然後,該值僅僅在子類中被改變。這就是為什麼第二個 print 語句的輸出是 1 2 1。
最後,如果該值在父類中被改變(例如,我們執行語句 Parent.x = 3),這個改變會影響到任何未重寫該值的子類當中的值(在這個示例中被影響的子類是 Child2)。這就是為什麼第三個 print 輸出是 3 2 3。
10、以下代碼將輸出什麼?
答案
以上代碼將輸出 [],並且不會導致一個 IndexError。
正如人們所期望的,試圖訪問一個超過列表索引值的成員將導致 IndexError(比如訪問以上列表的 list[10])。盡管如此,試圖訪問一個列表的以超出列表成員數作為開始索引的切片將不會導致 IndexError,並且將僅僅返回一個空列表。
【Python環境】12道 Python面試題總結
一個討厭的小問題是它會導致出現 bug ,並且這個問題是難以追蹤的,因為它在運行時不會引發錯誤。
11、以下的代碼的輸出將是什麼? 說出你的答案並解釋?
你將如何修改 extendList 的定義來產生期望的結果
以上代碼的輸出為:
許多人會錯誤的認為 list1 應該等於 [10] 以及 list3 應該等於 ['a']。認為 list 的參數會在 extendList 每次被調用的時候會被設置成它的默認值 []。
盡管如此,實際發生的事情是,新的默認列表僅僅只在函數被定義時創建一次。隨後當 extendList 沒有被指定的列表參數調用的時候,其使用的是同一個列表。這就是為什麼當函數被定義的時候,表達式是用默認參數被計算,而不是它被調用的時候。
因此,list1 和 list3 是操作的相同的列表。而 ````list2是操作的它創建的獨立的列表(通過傳遞它自己的空列表作為list``` 參數的值)。
extendList 函數的定義可以做如下修改,但,當沒有新的 list 參數被指定的時候,會總是開始一個新列表,這更加可能是一直期望的行為。
12、以下程序輸出什麼?
好
吧,第一行代碼覺對是我第一次見,第一行輸出的是[[], [], [], [], []],一個含有5個空列表的列表,而第二行輸出的是[[10],
[10], [10], [10],
[10]],我只能解釋為這5個列表指向了同一個列表,所以修改任意一個其它4個都會改變,可以用list[0]=10 斷開一個連接試試。
『柒』 如何理解和掌握Python垃圾回收機制
現在的高來級語言如java,c#等,都採用源了垃圾收集機制,而不再是c,c++里用戶自己管理維護內存的方式。自己管理內存極其自由,可以任意申請內存,但如同一把雙刃劍,為大量內存泄露,懸空指針等bug埋下隱患。
對於一個字元串、列表、類甚至數值都是對象,且定位簡單易用的語言,自然不會讓用戶去處理如何分配回收內存的問題。
『捌』 python的回收機制是什麼
Python中的垃圾回收機制總體上有三種,
引用計數
Python語言默認採用的垃圾收集機制是『引用計數法 Reference Counting』,該演算法最早George E. Collins在1960的時候首次提出,50年後的今天,該演算法依然被很多編程語言使用,『引用計數法』的原理是:每個對象維護一個ob_ref欄位,用來記錄該對象當前被引用的次數,每當新的引用指向該對象時,它的引用計數ob_ref加1,每當該對象的引用失效時計數ob_ref減1,一旦對象的引用計數為0,該對象立即被回收,對象佔用的內存空間將被釋放。它的缺點是需要額外的空間維護引用計數,這個問題是其次的,不過最主要的問題是它不能解決對象的「循環引用」,因此,也有很多語言比如Java並沒有採用該演算法做來垃圾的收集機制。
在上圖中,我們把小黑圈視為全局變數,也就是把它作為root object,從小黑圈出發,對象1可直達,那麼它將被標記,對象2、3可間接到達也會被標記,而4和5不可達,那麼1、2、3就是活動對象,4和5是非活動對象會被GC回收。
標記清除演算法作為Python的輔助垃圾收集技術主要處理的是一些容器對象,比如list、dict、tuple,instance等,因為對於字元串、數值對象是不可能造成循環引用問題。Python使用一個雙向鏈表將這些容器對象組織起來。不過,這種簡單粗暴的標記清除演算法也有明顯的缺點:清除非活動的對象前它必須順序掃描整個堆內存,哪怕只剩下小部分活動對象也要掃描所有對象。
分代回收
分代回收是一種以空間換時間的操作方式,Python將內存根據對象的存活時間劃分為不同的集合,每個集合稱為一個代,Python將內存分為了3「代」,分別為年輕代(第0代)、中年代(第1代)、老年代(第2代),他們對應的是3個鏈表,它們的垃圾收集頻率與對象的存活時間的增大而減小。新創建的對象都會分配在年輕代,年輕代鏈表的總數達到上限時,Python垃圾收集機制就會被觸發,把那些可以被回收的對象回收掉,而那些不會回收的對象就會被移到中年代去,依此類推,老年代中的對象是存活時間最久的對象,甚至是存活於整個系統的生命周期內。同時,分代回收是建立在標記清除技術基礎之上。分代回收同樣作為Python的輔助垃圾收集技術處理那些容器對象。
Python垃圾回收機制--完美講解! 東皇Amrzs
Python中的垃圾回收機制
『玖』 Python的垃圾回收機制(garbage collection)是什麼
這里能說的很多。你應該提到下面幾個主要的點:
Python在內存中存儲了每個對象的引版用計數(權reference count)。如果計數值變成0,那麼相應的對象就會小時,分配給該對象的內存就會釋放出來用作他用。
偶爾也會出現引用循環(reference cycle)。垃圾回收器會定時尋找這個循環,並將其回收。舉個例子,假設有兩個對象o1和o2,而且符合o1.x == o2和o2.x == o1這兩個條件。如果o1和o2沒有其他代碼引用,那麼它們就不應該繼續存在。但它們的引用計數都是1。來自三人行慕課
Python中使用了某些啟發式演算法(heuristics)來加速垃圾回收。例如,越晚創建的對象更有可能被回收。對象被創建之後,垃圾回收器會分配它們所屬的代(generation)。每個對象都會被分配一個代,而被分配更年輕代的對象是優先被處理的。
『拾』 python 什麼時候 垃圾回收
Python中的垃圾回收是以引用計數為主,分代收集為輔。引用計數的缺陷是循環引用的問題。
在Python中,如果一個對象的引用數為0,Python虛擬機就會回收這個對象的內存。
#encoding=utf-8
__author__ = '[email protected]'
class ClassA():
def __init__(self):
print 'object born,id:%s'%str(hex(id(self)))
def __del__(self):
print 'object del,id:%s'%str(hex(id(self)))
def f1():
while True:
c1=ClassA()
del c1
執行f1()會循環輸出這樣的結果,而且進程佔用的內存基本不會變動
object born,id:0x237cf58
object del,id:0x237cf58
c1=ClassA()會創建一個對象,放在0x237cf58內存中,c1變數指向這個內存,這時候這個內存的引用計數是1
del c1後,c1變數不再指向0x237cf58內存,所以這塊內存的引用計數減一,等於0,所以就銷毀了這個對象,然後釋放內存。
1、導致引用計數+1的情況
對象被創建,例如a=23
對象被引用,例如b=a
對象被作為參數,傳入到一個函數中,例如func(a)
對象作為一個元素,存儲在容器中,例如list1=[a,a]
2、導致引用計數-1的情況
對象的別名被顯式銷毀,例如del a
對象的別名被賦予新的對象,例如a=24
一個對象離開它的作用域,例如f函數執行完畢時,func函數中的局部變數(全局變數不會)
對象所在的容器被銷毀,或從容器中刪除對象
demo
def func(c,d):
print 'in func function', sys.getrefcount(c) - 1
print 'init', sys.getrefcount(11) - 1
a = 11
print 'after a=11', sys.getrefcount(11) - 1
b = a
print 'after b=1', sys.getrefcount(11) - 1
func(11)
print 'after func(a)', sys.getrefcount(11) - 1
list1 = [a, 12, 14]
print 'after list1=[a,12,14]', sys.getrefcount(11) - 1
a=12
print 'after a=12', sys.getrefcount(11) - 1
del a
print 'after del a', sys.getrefcount(11) - 1
del b
print 'after del b', sys.getrefcount(11) - 1
# list1.pop(0)
# print 'after pop list1',sys.getrefcount(11)-1
del list1
print 'after del list1', sys.getrefcount(11) - 1
輸出
init 24
after a=11 25
after b=1 26
in func function 28
after func(a) 26
after list1=[a,12,14] 27
after a=12 26
after del a 26
after del b 25
after del list1 24
問題:為什麼調用函數會令引用計數+2
3、查看一個對象的引用計數
sys.getrefcount(a)可以查看a對象的引用計數,但是比正常計數大1,因為調用函數的時候傳入a,這會讓a的引用計數+1
二.循環引用導致內存泄露
def f2():
while True:
c1=ClassA()
c2=ClassA()
c1.t=c2
c2.t=c1
del c1
del c2
執行f2(),進程佔用的內存會不斷增大。
object born,id:0x237cf30
object born,id:0x237cf58
創建了c1,c2後,0x237cf30(c1對應的內存,記為內存1),0x237cf58(c2對應的內存,記為內存2)這兩塊內存的引用計數都是1,執行c1.t=c2和c2.t=c1後,這兩塊內存的引用計數變成2.
在del c1後,內存1的對象的引用計數變為1,由於不是為0,所以內存1的對象不會被銷毀,所以內存2的對象的引用數依然是2,在del c2後,同理,內存1的對象,內存2的對象的引用數都是1。
雖然它們兩個的對象都是可以被銷毀的,但是由於循環引用,導致垃圾回收器都不會回收它們,所以就會導致內存泄露。
三.垃圾回收
deff3():
# print gc.collect()
c1=ClassA()
c2=ClassA()
c1.t=c2
c2.t=c1
del c1
del c2
print gc.garbage
print gc.collect() #顯式執行垃圾回收
print gc.garbage
time.sleep(10)
if __name__ == '__main__':
gc.set_debug(gc.DEBUG_LEAK) #設置gc模塊的日誌
f3()
輸出:
gc: uncollectable <ClassA instance at 0230E918>
gc: uncollectable <ClassA instance at 0230E940>
gc: uncollectable <dict 0230B810>
gc: uncollectable <dict 02301ED0>
object born,id:0x230e918
object born,id:0x230e940
4
垃圾回收後的對象會放在gc.garbage列表裡面
gc.collect()會返回不可達的對象數目,4等於兩個對象以及它們對應的dict
有三種情況會觸發垃圾回收:
1.調用gc.collect(),
2.當gc模塊的計數器達到閥值的時候。
3.程序退出的時候
四.gc模塊常用功能解析
gc模塊提供一個介面給開發者設置垃圾回收的選項。上面說到,採用引用計數的方法管理內存的一個缺陷是循環引用,而gc模塊的一個主要功能就是解決循環引用的問題。
常用函數:
1、gc.set_debug(flags)
設置gc的debug日誌,一般設置為gc.DEBUG_LEAK
2、gc.collect([generation])
顯式進行垃圾回收,可以輸入參數,0代表只檢查第一代的對象,1代表檢查一,二代的對象,2代表檢查一,二,三代的對象,如果不傳參數,執行一個full collection,也就是等於傳2。
返回不可達(unreachable objects)對象的數目
3、gc.set_threshold(threshold0[, threshold1[, threshold2])
設置自動執行垃圾回收的頻率。
4、gc.get_count()
獲取當前自動執行垃圾回收的計數器,返回一個長度為3的列表
5、gc模塊的自動垃圾回收機制
必須要import gc模塊,並且is_enable()=True才會啟動自動垃圾回收。
這個機制的主要作用就是發現並處理不可達的垃圾對象。
垃圾回收=垃圾檢查+垃圾回收
在Python中,採用分代收集的方法。把對象分為三代,一開始,對象在創建的時候,放在一代中,如果在一次一代的垃圾檢查中,改對象存活下來,就會被放到二代中,同理在一次二代的垃圾檢查中,該對象存活下來,就會被放到三代中。
gc模塊裡面會有一個長度為3的列表的計數器,可以通過gc.get_count()獲取。
例如(488,3,0),其中488是指距離上一次一代垃圾檢查,Python分配內存的數目減去釋放內存的數目,注意是內存分配,而不是引用計數的增加。例如:
print gc.get_count() # (590, 8, 0)
a = ClassA()
print gc.get_count() # (591, 8, 0)
del a
print gc.get_count() # (590, 8, 0)
3是指距離上一次二代垃圾檢查,一代垃圾檢查的次數,同理,0是指距離上一次三代垃圾檢查,二代垃圾檢查的次數。
gc模快有一個自動垃圾回收的閥值,即通過gc.get_threshold函數獲取到的長度為3的元組,例如(700,10,10)
每一次計數器的增加,gc模塊就會檢查增加後的計數是否達到閥值的數目,如果是,就會執行對應的代數的垃圾檢查,然後重置計數器
例如,假設閥值是(700,10,10):
當計數器從(699,3,0)增加到(700,3,0),gc模塊就會執行gc.collect(0),即檢查一代對象的垃圾,並重置計數器為(0,4,0)
當計數器從(699,9,0)增加到(700,9,0),gc模塊就會執行gc.collect(1),即檢查一、二代對象的垃圾,並重置計數器為(0,0,1)
當計數器從(699,9,9)增加到(700,9,9),gc模塊就會執行gc.collect(2),即檢查一、二、三代對象的垃圾,並重置計數器為(0,0,0)