日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
Python內(nèi)存分配,常駐內(nèi)存和測(cè)量

要精通一門語(yǔ)言,熟悉其內(nèi)容分配和使用機(jī)制很重要。對(duì)于編譯型語(yǔ)言比如C,C++,內(nèi)存的使用完全由程序員自己代碼分配和管理,所以對(duì)C,C++程序員內(nèi)存機(jī)制非常熟悉。但是對(duì)于動(dòng)態(tài)語(yǔ)言,比如Python,內(nèi)存在語(yǔ)言層自動(dòng)管理,所以程序員無(wú)需關(guān)注太多細(xì)節(jié),但是如果要想自己寫的代碼高效可靠,則也必須了解語(yǔ)言的內(nèi)存機(jī)制。本文蟲蟲給大家介紹Python語(yǔ)言的內(nèi)存機(jī)制,以及如何對(duì)其內(nèi)存進(jìn)行度量。

十余年建站經(jīng)驗(yàn), 成都網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè)客戶的見證與正確選擇。創(chuàng)新互聯(lián)提供完善的營(yíng)銷型網(wǎng)頁(yè)建站明細(xì)報(bào)價(jià)表。后期開發(fā)更加便捷高效,我們致力于追求更美、更快、更規(guī)范。

概述

考慮以下代碼:

 
 
 
 
  1. import numpy as np 
  2. cc= np.ones((1024, 1024, 1024, 3), dtype=np.uint8) 

該代碼將會(huì)創(chuàng)建一個(gè)3GB字節(jié)的數(shù)組,并且都用1來填充。同學(xué)們,可能會(huì)這樣預(yù)想運(yùn)行該代碼后,進(jìn)程將會(huì)自動(dòng)分配3GB的內(nèi)存用來使用,事實(shí)是不是如此呢?

測(cè)量?jī)?nèi)存的一種方法是使用“常駐內(nèi)存”,在Python中可以使用psutil庫(kù)工具獲取方便的這些信息,檢查當(dāng)前進(jìn)程的常駐內(nèi)存:

 
 
 
 
  1. import psutil 
  2. psutil.Process().memory_info().rss /(1024 * 1024) 
  3. 3093 

在該示例中,進(jìn)程使用了3093MB或3.09GB,與數(shù)組大小的無(wú)區(qū)別,和預(yù)想的一樣。

但是常駐內(nèi)存實(shí)際上沒那么簡(jiǎn)單。假設(shè)在機(jī)器上運(yùn)行一些耗內(nèi)存的任務(wù)。然后切換回解釋器,再次運(yùn)行完全相同的命令:

 
 
 
 
  1. psutil.Process().memory_info().rss / (1024 * 1024) 
  2. 2903.12109375 

這是怎么回事? 內(nèi)存少了200MB。

為了解釋這個(gè)現(xiàn)象,需要了解操作系統(tǒng)如何內(nèi)存管理機(jī)制。

簡(jiǎn)化模型

當(dāng)前正運(yùn)行的程序都會(huì)分配一些內(nèi)存,即從操作系統(tǒng)取回虛擬內(nèi)存中的地址。 虛擬內(nèi)存是一個(gè)特定于進(jìn)程的地址空間,本質(zhì)上是來自0至264-1,進(jìn)程可以讀取或?qū)懭胱止?jié)。

在C語(yǔ)言中,程序員可以使用malloc()或者mmap()函數(shù)進(jìn)行手動(dòng)內(nèi)存分配;而在Python中,我們只需創(chuàng)建對(duì)象,Python 解釋器將在底層自動(dòng)調(diào)用malloc()或者mmap()。然后該進(jìn)程可以讀取或?qū)懭朐撎囟ǖ刂泛瓦B續(xù)字節(jié)。

Linux下可以用ltrace工具跟蹤調(diào)用malloc(),運(yùn)行下面Python代碼:

 
 
 
 
  1. import numpy as np 
  2. cc = np.ones((170_000,), dtype=np.uint8) 

然后可以運(yùn)行l(wèi)trace:

 
 
 
 
  1. ltrace -e malloc python ones.py 
  2. ... 
  3. _multiarray_umath.cpython-39-x86_64-linux-gnu.so->malloc(170000) = 0x5638862a45e0 
  4. ... 

整個(gè)過程Python 創(chuàng)建一個(gè)NumPy數(shù)組。

在Python引擎NumPy調(diào)用malloc()。

這樣做的結(jié)果malloc()是內(nèi)存中的地址:0x5638862a45e0。

然后,用于實(shí)現(xiàn)NumPy的C代碼可以讀取和寫入該地址和下一個(gè)連續(xù)的169,999 個(gè)地址,每個(gè)地址代表虛擬內(nèi)存中的一個(gè)字節(jié)。

這 170,000個(gè)字節(jié)存儲(chǔ)在哪里?

它們可以存儲(chǔ)在RAM中;這是默認(rèn)設(shè)置。

它們可以存儲(chǔ)在計(jì)算機(jī)的硬盤驅(qū)動(dòng)器或磁盤上,即swap分區(qū)交換中。

一些字節(jié)可能存儲(chǔ)在 RAM 中,一些字節(jié)可能存儲(chǔ)在交換分區(qū)中。

常駐內(nèi)存

RAM很快,而硬盤IO很慢,但RAM很貴。通常電腦硬盤驅(qū)動(dòng)器空間比RAM多得多。例如,目前主流的計(jì)算機(jī)都會(huì)有2T左右的硬盤存儲(chǔ)空間,但只會(huì)16GB的RAM。

理想情況下,程序的所有內(nèi)存都將存儲(chǔ)在內(nèi)存RAM中,但計(jì)算機(jī)上運(yùn)行的各種進(jìn)程可能分配的內(nèi)存比RAM中可用的內(nèi)存多。如果發(fā)生這種情況,操作系統(tǒng)會(huì)將一些數(shù)據(jù)從RAM移動(dòng)或“交換”到硬盤驅(qū)動(dòng)器。必要時(shí),從交換分區(qū)中獲取數(shù)據(jù),并將未積極使用的數(shù)據(jù)置換進(jìn)去。

現(xiàn)在我們準(zhǔn)備定義我們的第一個(gè)內(nèi)存使用量度:常駐內(nèi)存。常駐內(nèi)存是進(jìn)程分配的內(nèi)存中有多少常駐或存儲(chǔ)在RAM中。

在第一個(gè)示例中,首先將所有3GB的已分配數(shù)組存儲(chǔ)在RAM中。

然后,當(dāng)運(yùn)行一些任務(wù)時(shí),加載這些任務(wù)需要分配很多RAM,因此操作系統(tǒng)會(huì)將一些數(shù)據(jù)從RAM交換到磁盤交換分區(qū)。結(jié)果,Python進(jìn)程的常駐內(nèi)存下降了:所有數(shù)據(jù)仍然可以訪問,但其中一些已移至磁盤交換分區(qū)。

分配內(nèi)存

測(cè)量分配內(nèi)存會(huì)很有用,無(wú)論操作系統(tǒng)是將數(shù)據(jù)放在RAM中還是將其交換到磁盤,總是3GB內(nèi)存,程序?qū)嶋H需要多少內(nèi)存。

在 Python 中(如果使用的是Linux 或macOS),可以使用Fil memory profiler測(cè)量分配的內(nèi)存,它專門測(cè)量峰值分配的內(nèi)存。對(duì)于之前的示例:

常駐內(nèi)存和分配內(nèi)存之間的權(quán)衡

常駐內(nèi)存存在一些問題:

  • 內(nèi)存的使用和測(cè)量會(huì)受到其他進(jìn)程的影響,由于其他進(jìn)程可能會(huì)爭(zhēng)搶常駐內(nèi)存導(dǎo)致使用的實(shí)際使用的RAM會(huì)變化。
  • 常駐內(nèi)存的上限是可用的物理RAM,所以一旦達(dá)到上限,就永遠(yuǎn)不會(huì)真正了解程序要求多少內(nèi)存。比如主機(jī)物理內(nèi)存16GB,對(duì)需要17GB內(nèi)存的程序和需要30GB 內(nèi)存的程序,它們駐留內(nèi)存的量都將一致,都將是16GB。
  • 另一方面,分配的內(nèi)存不受其他進(jìn)程的影響,并告訴程序?qū)嶋H請(qǐng)求的內(nèi)容。

當(dāng)然,常駐內(nèi)存確實(shí)比分配內(nèi)存的優(yōu)勢(shì):

  • 交換的內(nèi)存很可能永遠(yuǎn)不會(huì)被使用:想象一下創(chuàng)建一個(gè)數(shù)組,忘記刪除引用,然后在程序的其余部分不再實(shí)際使用它。
  • 更廣泛地說,由于駐留內(nèi)存從操作系統(tǒng)的角度衡量實(shí)際使用的內(nèi)存,因此它可以捕獲對(duì)分配的內(nèi)存跟蹤不可見的邊緣情況。

讓我們看一個(gè)這樣的邊緣情況的例子。

總結(jié)

到目前為止示例中,我們一直在分配充滿1的數(shù)組。如果測(cè)量已分配的內(nèi)存,則數(shù)組填充的內(nèi)容沒有區(qū)別:可以切換到創(chuàng)建充滿零的數(shù)組,并且仍然得到完全相同的結(jié)果。

但是在Linux 上,再看一個(gè)例子:

 
 
 
 
  1. import numpy as np 
  2. import psutil 
  3. arr = np.zeros((1024, 1024, 1024, 3), dtype=np.uint8) 
  4. psutil.Process().memory_info().rss/(1024 * 1024) 
  5. 28.5546875 

這次,還是分配了一個(gè)3GB的數(shù)組,但是給數(shù)組的元素都是零。然后測(cè)量常駐內(nèi)存——數(shù)組并沒有被計(jì)算到,常駐內(nèi)存只有29M。數(shù)組占用的內(nèi)存呢?

事實(shí)證明,Linux 不會(huì)費(fèi)心將所有這些零存儲(chǔ)在RAM中。而只是在實(shí)際訪問數(shù)據(jù)時(shí)向RAM添加零塊,并不會(huì)實(shí)際分配內(nèi)存。

最后,需要提及的是,我們?cè)谡f的內(nèi)存使用模型也是理想狀態(tài)的。還沒有包括文件緩存、分配器中的內(nèi)存碎片或其他可用指標(biāo)等。

話雖如此,對(duì)于許多應(yīng)用程序來說,分配的內(nèi)存可能足以作為幫助優(yōu)化程序內(nèi)存使用的必要措施。


當(dāng)前名稱:Python內(nèi)存分配,常駐內(nèi)存和測(cè)量
標(biāo)題URL:http://www.dlmjj.cn/article/cddshoh.html