標籤:highlight size inf 方法 整數 注意 輸出 估算 port
『Python』記憶體分析_List對象記憶體佔用分析
在Python中,列表是一個動態指標數組,而array模組所提供的array對象則是儲存相同類型的數值的動態數組。由於array直接儲存值,因此它所使用的記憶體比列表少。列表和array都是動態數組,因此往其中添加新元素,而沒有空間儲存新的元素時,它們會自動重新分配記憶體塊,並將原來的記憶體中的值複製到新的記憶體塊中。為了減少重新分配記憶體的次數,通常每次重新分配時,大小都為原來的k倍。k值越大,則重新分配記憶體的次數越少,但浪費的空間越多。本節通過一系列的實驗觀察列表和array的記憶體配置模式。
一、通過getsizeof()計算資料行表的增長模式step1
sys.getsizeof()可以獲得列表所佔用的記憶體大小。請編寫程式計算一個長度為10000的列表,它的每個下標都儲存列表增長到此下標時的大小:
import sys# 【你的程式】計算size列表,它的每個小標都儲存增長到此下標時size列表的大小size = []for i in range(10000): size.append(sys.getsizeof(size))import pylab as plpl.plot(size, lw=2, c=‘b‘)pl.show()
圖中每個階梯跳變的位置都表示一次記憶體配置,而每個階梯的長度表示記憶體配置多出來的大小。
step2
請編寫程式計算表示每次分配記憶體時列表的記憶體大小的resize_pos數組:
import numpy as np#【你的程式】計算resize_pos,它的每個元素是size中每次分配記憶體的位置# 可以使用NumPy的diff()、where()、nonzero()快速完成此計算。size = []for i in range(10000): size.append(sys.getsizeof(size))size = np.array(size)new_size = np.diff(size)resize_pos = size[np.where(new_size)]# resize_pos = size[np.nonzero(new_size)]pl.plot(resize_pos, lw=2)pl.show()print ("list increase rate:")tmp = resize_pos[25:].astype(np.float) # ?print (np.average(tmp[1:]/tmp[:-1])) # ?
由圖可知曲線呈指數增長,第45次分配記憶體時,列表的大小已經接近10000。
?為了計算增長率,只需要計算resize_pos數組前後兩個值的商的平均值即可。
?為了提高精度,我們只計算後半部分的平均值,注意需要用astype()方法將整數數群組轉換為浮點數數組。程式的輸出如下:
list increase rate:
1.12754776209
【注】np.where索引定位的兩種用法,np.nonzero非零值bool判斷的用法,np.diff差分函數的用法。
step3
我們可以用scipy.optimize.curve_fit()對resize_pos數組進行擬合,擬合函數為指數函數:
請編寫程式用上面的公式對resize_pos數組進行擬合:
from scipy.optimize import curve_fit#【你的程式】用指數函數對resize_pos數組進行擬合def func(x, a, b, c, d): return a * np.exp(b * x + c) + dxdata = range(len(resize_pos))ydata = resize_pospopt, pcov = curve_fit(func, xdata, ydata) y = [func(i, *popt) for i in xdata]pl.plot(xdata, y, lw=1, c=‘r‘)pl.plot(xdata, ydata, lw=1, c=‘b‘)pl.show()print ("list increase rate by curve_fit:")print (10**popt[1])
list increase rate by curve_fit: 1.31158606108
【注意】本程式中對於scipy中的指數擬合做了示範。
二、通過運算時間估算array記憶體配置情況
遺憾的是,無論array對象的長度是多少,sys.getsizeof()的結果都不變。因此無法用上節的方法計算array對象的增長因子。
由於記憶體配置時會耗費比較長的時間,因此可以通過測量每次增加元素的時間,找到記憶體配置時的長度。請編寫測量增加元素的時間的程式:
from array import arrayimport time#【你的程式】計算往array中添加元素的時間timestimes = []times_step = []arrays = [array(‘l‘) for i in range(1000)]start = time.time()for i in range(1000): start_step = time.time() [a.append(i) for a in arrays] end = time.time() times_step.append(end-start_step) times.append(end-start)pl.figure()pl.plot(times)pl.figure()pl.plot(times_step)pl.show()
輸出兩幅圖,前面的表示元素個數對應的程式總耗時,後面的表示每一次添加元素這一過程的耗時,注意,這張圖只有在array數量較大時才是這個形狀,數組數量不夠時折線圖差異很大。
進一步的,我們分析一下耗時顯著大於附近點(極大值)的時刻的序列對應此時元素數量的折線圖。
ts = np.array(times_step)le = range(np.sum(ts>0.00025))si = np.squeeze(np.where(ts>0.00025))pl.plot(le,si,lw=2)pl.show()
『Python』記憶體分析_list和array的記憶體增長模式