1. 程式人生 > >Matlab記憶體問題(轉載)

Matlab記憶體問題(轉載)

用 Matlab 進行大規模科學計算或模擬時,記憶體是一個需要時常注意的問題。在matlab裡執行

>>system_dependent memstats

就可以看到記憶體的使用狀況。當你寫的 Matlab 程式跳出“Out of Memory” 時,以下幾點措施是需要優先考慮的解決方法:

1. 升級記憶體

2. 升級64位系統

3. 增加虛擬記憶體

4. 採用3GB開關啟動系統

由於32位 Windows 作業系統的限制,每個程序只能使用最多 2GB 的虛擬記憶體地址空間,因此 Matlab 的可分配記憶體也受到相應的限制。Matlab 7.0.1 引進了新的記憶體管理機制,可以利用 Windows 的 3GB 開關,使用 3GB 開關啟動的 Windows 每個程序可以在多分配 1 GB 的虛擬地址空間。具體做法是:修改C盤根目錄 boot.ini 啟動選項加上 /3G,例如:

multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional" /noexecute=optin /fastdetect /3G

5. 如果必有必要,不要啟動java虛擬機器,採用matlab -nojvm啟動 (在快捷方式屬性裡面的 "..../matlab.exe") 改為("...../matlab.exe" - nojvm)

6. 關閉Matlab Server

7. Windows中字型、視窗等都是要佔用系統資源的,所以在Matlab執行時儘量不要開啟不用的視窗。

除此以外,更關鍵的是需要弄清楚以下幾個問題:

問題一:Matlab是如何儲存矩陣的?

Matlab中矩陣是以Block,也就是塊的形式儲存的。也就是說,當Matlab在為即將儲存的矩陣劃分塊時,如果沒有相應大小的連續記憶體,即使實際記憶體沒有被完全使用,它還是會報告“Out of Memory”。

問題二:如何高效使用Memory?
Matlab 中陣列必須佔用連續分配的記憶體段,當無法為新建的陣列分配連續的記憶體段的時候,”Out of Memory” 就會出現。在使用的過程中,由於儲存單元的不斷的被分配和清除,反覆分配和釋放陣列會使記憶體被分割成不連續的區域,可用的連續記憶體段減少,很容易造成“Out of Memory”。因此當 Matlab 剛剛啟動時其連續記憶體最多,此時往往可以新建非常大的陣列,這一點可以用命令 feature(’memstats’)(在 7.0 版本以上)看出。如果現實的最大連續記憶體段很小,但實際可用記憶體(非連續的)仍舊很多,則表明記憶體中碎片太多了。此時可以考慮用 pack 命令,pack 命令的作用就是將所有記憶體中的陣列寫入硬碟,然後重新建立這些陣列,以減少記憶體碎片。此外,在命令列或者程式中都可以使用 clear 命令,隨時減少不必要的記憶體。


因此,治本的方法如下:

1. 在命令列輸入 pack 整理記憶體空間

當記憶體被分為很多碎片以後,其實本身可能有很大的空間,只是沒有作構的連續空間即大的Block而已。如果此時Out of Memory,此時使用pack命令可以很好的解決此問題。

2. 使用稀疏矩陣或將矩陣轉化成稀疏形式 sparse

如果矩陣中有大量的0,最好儲存成稀疏形式。稀疏形式的矩陣使用記憶體更少,執行時間更短。例如:
000×1000的矩陣X,它2/3的元素為0,使用兩種儲存方法的比較:

Name
Size
Bytes
Class

X
1000x1000
8000000
double array

Y
1000x1000
4004000
double array (sparse)

3. 儘量避免產生大的瞬時變數,把沒必要的變數clear掉或當它們不用的時候應該及時clear。

4. 減少變數,儘量的重複使用變數(跟不用的clear掉一個意思)。

5. 把有用的變數先save,後clear 掉,需要時再讀出來。

下面介紹一下關於clear、save、load的特殊用法,這對在for或while等多重迴圈裡出現out of memory非常有效。

for k = 1:N % N為迴圈次數
% ---------------------
var0 = k; % 獲得變數var0 
%----------------------
string = [sprintf('var_%d', k) ' = var0;' ];
eval_r(string); % 等價於 var_k = var0;
save(sprintf('var_%d.mat', k), sprintf('var_%d')); % 等價於 save var_k.mat var_k
clear(sprintf('var_%d')); % 等價於 clear var_k
end

如果要讀取剛才存取的變數var_k, (k = 1,2, ..., N). 那麼,可以使用如下用法:

for k = 1:N
 load(sprintf('var_%d.mat', k));  % 等價於 load var_k.mat k = 1,2, ..., N
end

另外,還有一些非常有用的用法。如果用清除剛才讀取的變數 var_k, k = 1, 2, ..., N

clear '-regexp' '^var_'  % 清除所有以“ var_ ”開頭的變數

還有很多關於save、clear、load等用法,具體help一下。

6. 使用單精度 single 短整數替代雙精度 double

Matlab 預設的數字型別是雙精度浮點數 (double),每個雙浮點數佔用 8 個位元組。對於一些整數操作來說,使用雙浮點數顯得很浪費。在 Matlab 中可以在預先分配陣列時指定使用的數字型別如以下命令:zero(10, 10, ‘uint8′) 。對於浮點數,在很多精度要求不高的情況下,可以使用4個位元組的單浮點數 (single),可以減少一半的記憶體。關於單、雙浮點數的精度對照如下,以便根據需要選擇使用:
single: 精度 (1.1921e-007) 最大數 (3.4028e+038)
double: 精度 (2.2204e-016) 最大數 (1.7977e+308)

7. 為矩陣變數預製記憶體而不是動態分配

在動態分配的過程中,由於開始Matlab所用的Block隨著矩陣的增大而連續的為此矩陣分配記憶體,但是由於Block的不連續性,很有可能最開始分配的Block不能滿足儲存的需要,Matlab只好移動此Block以找到更大的Block來儲存,這樣在移動的過程中不但佔用了大量的時間,而且很有可能它找不到更大的塊,導致Out of Memory。而當你為矩陣變數預製記憶體時,Matlab會在計算開始前一次性找到最合適的Block,此時就不用為變數連續的分配記憶體。比較下面兩個程式:

for k = 2:1000
x(k) = x(k-1) + 5;
end

x = zeros(1, 1000);
for k = 2:1000
x(k) = x(k-1) + 5;
end

顯然,第二個更好!!!最好的方法是,在程式一開始就位所有大的矩陣變數預製存儲存單元!!!

8. 儘量早的為大的矩陣變數預製記憶體

Matlab使用heap method管理記憶體。當在Matlab heap中沒有足夠的記憶體使用時,它會向系統請求記憶體。但是隻要記憶體碎片可以存下當前的變數,Matlab會重新使用記憶體。比如:

a = rand(1e6,1);
b = rand(1e6,1);
使用大約15.4 MB RAM

c = rand(2.1e6,1);
使用近似16.4 MB RAM

a = rand(1e6,1);
b = rand(1e6,1);
clear
c = rand(2.1e6,1);
使用32.4 MB RAM

Matlab不能使用a、b被clear的空間,因為它們均小於2.1 MB,而同時它們也很可能是不連續的。最好的方法:

c = rand(2.1e6,1);
clear
a = rand(1e6,1);
b = rand(1e6,1);
使用16.4 MB RAM

9. 如果可行的話,將一個大的矩陣劃分為幾個小的矩陣,這樣每一次使用的記憶體減少。