當前位置:首頁 » 編程語言 » python堆內存

python堆內存

發布時間: 2022-11-28 12:06:28

1. python如何進行內存管理

Python的內存管理主要有三種機制:引用計數機制,垃圾回收機制和內存池機制。
引用計數機制
簡介
python內部使用引用計數,來保持追蹤內存中的對象,Python內部記錄了對象有多少個引用,即引用計數,當對象被創建時就創建了一個引用計數,當對象不再需要時,這個對象的引用計數為0時,它被垃圾回收。
特性
1.當給一個對象分配一個新名稱或者將一個對象放入一個容器(列表、元組或字典)時,該對象的引用計數都會增加。
2.當使用del對對象顯示銷毀或者引用超出作用於或者被重新賦值時,該對象的引用計數就會減少。
3.可以使用sys.getrefcount()函數來獲取對象的當前引用計數。多數情況下,引用計數要比我們猜測的大的多。對於不可變數據(數字和字元串),解釋器會在程序的不同部分共享內存,以便節約內存。
垃圾回收機制
特性
1.當內存中有不再使用的部分時,垃圾收集器就會把他們清理掉。它會去檢查那些引用計數為0的對象,然後清除其在內存的空間。當然除了引用計數為0的會被清除,還有一種情況也會被垃圾收集器清掉:當兩個對象相互引用時,他們本身其他的引用已經為0了。
2.垃圾回收機制還有一個循環垃圾回收器, 確保釋放循環引用對象(a引用b, b引用a, 導致其引用計數永遠不為0)。
內存池機制
簡介
在Python中,許多時候申請的內存都是小塊的內存,這些小塊內存在申請後,很快又會被釋放,由於這些內存的申請並不是為了創建對象,所以並沒有對象一級的內存池機制。這就意味著Python在運行期間會大量地執行malloc和free的操作,頻繁地在用戶態和核心態之間進行切換,這將嚴重影響Python的執行效率。為了加速Python的執行效率,Python引入了一個內存池機制,用於管理對小塊內存的申請和釋放。
內存池概念
內存池的概念就是預先在內存中申請一定數量的,大小相等的內存塊留作備用,當有新的內存需求時,就先從內存池中分配內存給這個需求,不夠了之後再申請新的內存。這樣做最顯著的優勢就是能夠減少內存碎片,提升效率。內存池的實現方式有很多,性能和適用范圍也不一樣。
特性
1.Python提供了對內存的垃圾收集機制,但是它將不用的內存放到內存池而不是返回給操作系統。
2.Pymalloc機制。為了加速Python的執行效率,Python引入了一個內存池機制,用於管理對小塊內存的申請和釋放。
3.Python中所有小於256個位元組的對象都使用pymalloc實現的分配器,而大的對象則使用系統的 malloc。
4.對於Python對象,如整數,浮點數和List,都有其獨立的私有內存池,對象間不共享他們的內存池。也就是說如果你分配又釋放了大量的整數,用於緩存這些整數的內存就不能再分配給浮點數。

2. python的內存管理機制

論壇

活動

招聘

專題

打開CSDN APP
Copyright © 1999-2020, CSDN.NET, All Rights Reserved

登錄

XCCS_澍
關注
Python 的內存管理機制及調優手段? 原創
2018-08-05 06:50:53

XCCS_澍

碼齡7年

關注
內存管理機制:引用計數、垃圾回收、內存池。
一、引用計數:
    引用計數是一種非常高效的內存管理手段, 當一個 Python 對象被引用時其引用計數增加 1, 當其不再被一個變數引用時則計數減 1. 當引用計數等於 0 時對象被刪除。
二、垃圾回收 :
1. 引用計數
      引用計數也是一種垃圾收集機制,而且也是一種最直觀,最簡單的垃圾收集技術。當 Python 的某個對象的引用計數降為 0 時,說明沒有任何引用指向該對象,該對象就成為要被回收的垃圾了。比如某個新建對象,它被分配給某個引用,對象的引用計數變為 1。如果引用被刪除,對象的引用計數為 0,那麼該對象就可以被垃圾回收。不過如果出現循環引用的話,引用計數機制就不再起有效的作用了
2. 標記清除
     如果兩個對象的引用計數都為 1,但是僅僅存在他們之間的循環引用,那麼這兩個對象都是需要被回收的,也就是說,它們的引用計數雖然表現為非 0,但實際上有效的引用計數為 0。所以先將循環引用摘掉,就會得出這兩個對象的有效計數。
3. 分代回收
     從前面「標記-清除」這樣的垃圾收集機制來看,這種垃圾收集機制所帶來的額外操作實際上與系統中總的內存塊的數量是相關的,當需要回收的內存塊越多時,垃圾檢測帶來的額外操作就越多,而垃圾回收帶來的額外操作就越少;反之,當需回收的內存塊越少時,垃圾檢測就將比垃圾回收帶來更少的額外操作。

3. Python如何進行內存管理

Python是如何進行內存管理的?

答:從三個方面來說,一對象的引用計數機制,二垃圾回收機制,三內存池機制。

一、對象的引用計數機制

Python內部使用引用計數,來保持追蹤內存中的對象,所有對象都有引用計數。

引用計數增加的情況:

1,一個對象分配一個新名稱

2,將其放入一個容器中(如列表、元組或字典)

引用計數減少的情況:

1,使用del語句對對象別名顯示的銷毀

2,引用超出作用域或被重新賦值

Sys.getrefcount( )函數可以獲得對象的當前引用計數

多數情況下,引用計數比你猜測得要大得多。對於不可變數據(如數字和字元串),解釋器會在程序的不同部分共享內存,以便節約內存。

相關推薦:《Python視頻教程》

二、垃圾回收

1,當一個對象的引用計數歸零時,它將被垃圾收集機制處理掉。

2,當兩個對象a和b相互引用時,del語句可以減少a和b的引用計數,並銷毀用於引用底層對象的名稱。然而由於每個對象都包含一個對其他對象的應用,因此引用計數不會歸零,對象也不會銷毀。(從而導致內存泄露)。為解決這一問題,解釋器會定期執行一個循環檢測器,搜索不可訪問對象的循環並刪除它們。

三、內存池機制

Python提供了對內存的垃圾收集機制,但是它將不用的內存放到內存池而不是返回給操作系統。

1,Pymalloc機制。為了加速Python的執行效率,Python引入了一個內存池機制,用於管理對小塊內存的申請和釋放。

2,Python中所有小於256個位元組的對象都使用pymalloc實現的分配器,而大的對象則使用系統的malloc。

3,對於Python對象,如整數,浮點數和List,都有其獨立的私有內存池,對象間不共享他們的內存池。也就是說如果你分配又釋放了大量的整數,用於緩存這些整數的內存就不能再分配給浮點數。

4. Python內存駐留機制

字元串駐留機制在許多面向對象編程語言中都支持,比如Java、python、Ruby、PHP等,它是一種數據緩存機制,對不可變數據類型使用同一個內存地址,有效的節省了空間,本文主要介紹Python的內存駐留機制。

字元串駐留就是每個字元串只有一個副本,多個對象共享該副本,駐留只針對不可變數據類型,比如字元串,布爾值,數字等。在這些固定數據類型處理中,使用駐留可以有效節省時間和空間,當然在駐留池中創建或者插入新的內容會消耗一定的時間。

下面舉例介紹python中的駐留機制。

在Python對象及內存管理機制一文中介紹了python的參數傳遞以及以及內存管理機制,來看下面一段代碼:

知道結果是什麼嗎?下面是執行結果:

l1和l2內容相同,卻指向了不同的內存地址,l2和l3之間使用等號賦值,所以指向了同一個對象。因為列表是可變對象,每創建一個列表,都會重新分配內存,列表對象是沒有「內存駐留」機制的。下面來看不可變數據類型的駐留機制。

Jupyter或者控制台交互環境 中執行下面代碼:

執行結果:

可以發現a1和b1指向了不同的地址,a2和b2指向了相同的地址,這是為什麼呢?

因為啟動時,Python 將一個 -5~256 之間整數列表預載入(緩存)到內存中,我們在這個范圍內創建一個整數對象時,python會自動引用緩存的對象,不會創建新的整數對象。

浮點型不支持:

如果上面的代碼在非交互環境,也就是將代碼作為python腳本運行的結果是什麼呢?(運行環境為python3.7)

全為True,沒有明確的限定臨界值,都進行了駐留操作。這是因為使用不同的環境時,代碼的優化方式不同。

Jupyter或者控制台交互環境 中:

滿足標識符命名規范的字元:

結果:

乘法獲取字元串(運行環境為python3.7)

結果:

在非交互環境中:

注意: 字元串是在編譯時進行駐留 ,也就是說,如果字元串的值不能在編譯時進行計算,將不會駐留。比如下面的例子:

在交互環境執行結果如下:

都指向不同的內存。

python 3.7 非交互環境執行結果:

發現d和e指向不同的內存,因為d和e不是在編譯時計算的,而是在運行時計算的。前面的 a = 'aa'*50 是在編譯時計算的。

除了上面介紹的python默認的駐留外,可以使用sys模塊中的intern()函數來指定駐留內容

結果:

使用intern()後,都指向了相同的地址。

本文主要介紹了python的內存駐留,內存駐留是python優化的一種策略,注意不同運行環境下優化策略不一樣,不同的python版本也不相同。注意字元串是在編譯時進行駐留。

--THE END--

5. Python 列表內存淺析

序列是Python中最基本的數據結構。序列是一種數據存儲方式,用來存儲一系列的數據。

在內存中,序列就是一塊用來存放多個值的連續的內存空間。比如一個整數序列[10,20,30,40]

序列中的每個元素都分配一個數字 - 它的位置,或索引。第一個索引是0,第二個索引是1,依此類推。

列表:用於存儲任意數目、任意類型的數據集合。

列表是內置可變序列,是包含多個元素的有序連續的內存空間。列表定義的標准語法格式:

其中,10,20,30,40 這些稱為:列表a的元素。

列表中的元素可以各不相同,可以是任意類型。比如:a = [10,20,"abc",True,[]]

當列表增加元素時,列表會自動進行內存管理,減少了程序員的負擔。但是列表元素大量移動,效率低所以一般建議在尾部添加。

本地電腦運行結果:

列表是可變數據類型,地址不變,值可變。因此,添加新的值之後,地址也是不變的。

解析:在索引2處要引用50這個元素

申請了8個內存空間但是list實際用來存儲元素只使用了其中5個內存空間
insert的時間復雜度是O(n)

pop () 方法 刪除並返回指定位置的元素,如果未指定位置則默認操作

pop () 方法 刪除並返回指定位置的元素,如果未指定位置則默認操作

結果運行:

6. python跑了一個小時正常嗎

python跑了一個小時不正常。python跑時間超過半小時會發生內存泄漏的情況,是指程序中己動態分配的堆內存由於某種原因程序未釋放或無法釋放,造成系統內存的浪費,導致程序運行速度減慢甚至系統崩潰等嚴重後果。我的程序正好有大量的循環,因此也給不斷累積的內存泄漏提供了條件。

python特點

python是一種計算機程序設計語言,python是用來編寫應用程序的高級編程語言。完成同一個任務,python的代碼量很少,但是代碼少的代價是運行速度慢。python就為我們提供了非常完善的基礎代碼庫,覆蓋了網路、文件、GUI、資料庫、文本等大量內容,被形象地稱作內置電池。用python開發,許多功能不必從零編寫,直接使用現成的即可。

7. Python 的內存管理機制

Python採用自動內存管理,即Python會自動進行垃圾回收,不需要像C、C++語言一樣需要程序員手動釋放內存,手動釋放可以做到實時性,但是存在內存泄露、空指針等風險。

Python自動垃圾回收也有自己的優點和缺點:優點:

缺點:

Python的垃圾回收機制採用 以引用計數法為主,分代回收為輔 的策略。

先聊引用計數法,Python中每個對象都有一個核心的結構體,如下

一個對象被創建時,引用計數值為1,當一個變數引用一個對象時,該對象的引用計數ob_refcnt就加一,當一個變數不再引用一個對象時,該對象的引用計數ob_refcnt就減一,Python判斷是否回收一個對象,會將該對象的引用計數值ob_refcnt減一判斷結果是否等於0,如果等於0就回收,如果不等於0就不回收,如下:

一個對象在以下三種情況下引用計數會增加:

一個對象在以下三種情況引用計數會減少:

驗證案例:

運行結果:

事實上,關於垃圾回收的測試,最好在終端環境下測試,比如整數257,它在PyCharm中用下面的測試代碼列印出來的結果是4,而如果在終端環境下列印出來的結果是2。這是因為終端代表的是原始的Python環境,而PyCharm等IDE做了一些特殊處理,在Python原始環境中,整數緩存的范圍是在 [-5, 256] 的雙閉合區間內,而PyCharm做了特殊處理之後,PyCharm整數緩存的范圍變成了 [-5, 無窮大],但我們必須以終端的測試結果為主,因為它代表的是原始的Python環境,並且代碼最終也都是要發布到終端運行的。

好,那麼回到終端,我們來看兩種特殊情況

前面學習過了,整數緩存的范圍是在 [-5, 256] 之間,這些整數對象在程序載入完全就已經駐留在內存之中,並且直到程序結束退出才會釋放佔有的內存,測試案例如下:

如果字元串的內容只由字母、數字、下劃線構成,那麼它只會創建一個對象駐留在內存中,否則,每創建一次都是一個新的對象。

引用計數法有缺陷,它無法解決循環引用問題,即A對象引用了B對象,B對象又引用了A對象,這種情況下,A、B兩個對象都無法通過引用計數法來進行回收,有一種解決方法是程序運行結束退出時進行回收,代碼如下:

前面講過,Python垃圾回收機制的策略是 以引用計數法為主,以分代回收為輔 。分代回收就是為了解決循環引用問題的。

Python採用分代來管理對象的生命周期:第0代、第1代、第2代,當一個對象被創建時,會被分配到第一代,默認情況下,當第0代的對象達到700個時,就會對處於第0代的對象進行檢測和回收,將存在循環引用的對象釋放內存,經過垃圾回收後,第0代中存活的對象會被分配為第1代,同樣,當第1代的對象個數達到10個時,也會對第1代的對象進行檢測和回收,將存在循環引用的對象釋放內存,經過垃圾回收後,第1代中存活的對象會被分配為第2代,同樣,當第二代的對象個數達到10個時,也會對第2代的對象進行檢測和回收,將存在循環引用的對象釋放內存。Python就是通過這樣一種策略來解決對象之間的循環引用問題的。

測試案例:

運行結果:

如上面的運行結果,當第一代中對象的個數達到699個即將突破臨界值700時(在列印699之前就已經回收了,所以看不到698和699)進行了垃圾回收,回收掉了循環引用的對象。

第一代、第二代、第三代分代回收都是有臨界值的,這個臨界值可以通過調用 gc.get_threshold 方法查看,如下:

當然,如果對默認臨界值不滿意,也可以調用 gc.set_threshold 方法來自定義臨界值,如下:

最後,簡單列出兩個gc的其它方法,了解一下,但禁止在程序代碼中使用

以上就是對Python垃圾回收的簡單介紹,當然,深入研究肯定不止這些內容,目前,了解到這個程度也足夠了。

8. Python是怎樣管理內存的

Python中的內存管理是由Python私有堆空間管理,所以Python對象和數據結構都位於私有堆中,程序員無法訪問此私有堆,Python解釋器負責處理這個問題。
Python對象的堆空間分配由Python的內存管理器完成,核心API提供了一些程序員編寫代碼的工具。
Python還有一個內存的垃圾收集器,可以回收所有未使用的內存,並使其可用於堆空間。

9. python的內存問題該這么解決

1.沒有開gc,或者gc設為debug狀態,導致交叉引用沒有被回收調
2.如果一個數據在邏輯上不應該存在,但是因為代碼上沒有做相關清除操作,導致他還存在,也是一種泄漏
舉個栗子,例如我要記錄最近50天的某個基金的日化收益率,定義一個全局的字典global_dict,運行了一個腳本進行計算,沒10分鍾算一次,但是我沒有進行clear操作,每次的計算只是單純的賦值dict[date] = rate,按理來說dict["五十天前"]的收益率都是不需要的,就是一種泄漏。
3.這種情況出現在python3.4之前,因為3.4已經修復了,是這樣的,如果一個類定義了__del__,並且該類存在循環引用的情況,這時候gc就會把這個類放在gc.garbage當中,不會去做回收,可以說是跳出了分代回收的機制,但是3.4之後的版本就沒有這種情況,會把他回收調。

10. Python 多進程內存佔用問題

當我們有一個很長很長的任務隊列(mission_list)和閾值對應的一個處理函數(missionFunction)時,我們一般採用如下的方式進行處理:

但是,如果這任務列表很長很長,處理函數很復雜(佔用cpu)時,單核往往需要很長的時間進行處理,此時,Multiprocess便可以極大的提高我們程序的運行速度,相關內容請借鑒 multiprocessing --- 基於進程的並行 — Python 3.10.4 文檔。

以上這種場景下,推薦大家採用最簡單的進程池+map的方法進行處理,標準的寫法, chunksize要借鑒官方的說法,最好大一點

但是!!!! 如果我們的任務列表非常的長,這會導致多進程還沒跑起來之前,內存已經撐爆了,任務自然沒法完成,此時我們有幾種辦法進行優化:

進程的啟動方法有三種,可參考官方文檔:

[圖片上傳失敗...(image-48cd3c-1650511153989)]

linux環境下,使用forkserver可以節省很多的內存空間, 因為進程啟動的是一個服務,不會把主進程的數據全部復制

採用imap會極大的節省空間,它返回的是一個迭代器,也就是結果列表:

但注意,以上寫法中,你寫的結果迭代部分必須寫在with下面。或者採用另一種寫法:

還有最後一種,當你的mission list實在太大了,導致你在生成 mission list的時候已經把內存撐爆了,這個時候就得優化 mission_list了,如果你的mission_list是通過一個for循環生成的,你可以使用yield欄位,將其封裝為一個迭代器,傳入進程池:

這樣子,我們就封裝好了mission_list,它是一個可迭代對象,在取數據的時候才會將數據拉到內存

我在項目中結合了後兩種方法,原本256G的內存都不夠用,但在修改後內存只佔用了不到10G。希望能夠幫助到你

熱點內容
網路設置里沒有伺服器是什麼 發布:2025-01-18 09:52:19 瀏覽:343
阿里雲esc伺服器系統 發布:2025-01-18 09:49:16 瀏覽:790
你們家的無線網密碼是多少 發布:2025-01-18 09:47:50 瀏覽:729
renderscriptandroid 發布:2025-01-18 09:32:18 瀏覽:993
安卓手機如何拍游戲素材 發布:2025-01-18 09:30:59 瀏覽:348
廣州日立壓縮機有限公司 發布:2025-01-18 09:15:08 瀏覽:624
伺服器兩條寬頻如何疊加網速 發布:2025-01-18 08:52:17 瀏覽:731
oracle存儲過程集合 發布:2025-01-18 08:42:39 瀏覽:885
洋蔥數學緩存 發布:2025-01-18 08:38:36 瀏覽:918
電影的文件夾都是 發布:2025-01-18 08:21:49 瀏覽:835