2011年4月30日 星期六

[matlab] Out of memory

最近寫的matlab程式需要宣告一大塊matrix來存放資料,導致產生了out of memory的warning,造成這個問題的原因其實有很多種,但私心總是覺得「不是我的錯!」,因此便展開一系列解決之道。


在matlab command window中出現在訊息是「Out of memory. Type HELP MEMORY for your options.」,此時如果輸入memory後就可以產生以下訊息:
Maximum possible array:             156 MB (1.638e+008 bytes) *
Memory available for all arrays:    740 MB (7.756e+008 bytes) **
Memory used by MATLAB:             1054 MB (1.105e+009 bytes)
Physical Memory (RAM):             3070 MB (3.219e+009 bytes)
*  Limited by contiguous virtual address space available.
** Limited by virtual address space available.
不同於一般我們對compiler的認知,matlab在宣告變數時所需要的記憶體空間,必須是連續的,因此第一項指的就是matlab所握有的記憶體中最大的連續區塊大小。要解決這個問題,原則上有兩個方向:
  1. 加大可使用的連續記憶體
  2. 減少程式中無用的記憶體

    加大可使用的連續記憶體

    參考官方說明,如果跟我一樣是用32-bit OS的話,每個process有最大記憶體限制2GB,光是matlab與javaVM的初始化可能就吃掉超過一半,以現今電腦的等級來看,通常是不會有實體/虛擬記憶體不足的問題,解決方案有以下幾種:

    a. chkmem

    這個工具可在這裡下載,呼叫該.m檔後它會列出目前matlab吃掉的記憶體中前三大空間的始作俑者,如果其中包含開機時會啟動的java service的話可以考慮關掉它。如果想要看所有fragments可輸入指令「feature dumpmem」。要清除這些大fragments的方法,可參考Avoiding 'Out of Memory' Errors第二章Section 2: Maximizing Size of Largest Contiguous Block of Memory (32-bit Windows only)。
    不過,這個方法不適合於我,因為我的前三名都是<anonymous>。。。

    b. Using the 3GB Switch on Windows Systems

    這個方法是加大每個process可以使用的最大記憶體空間,從原本的2GB提高到3GB。方法是修改C槽下的boot.ini檔,這個檔案是windows開機前的設定檔,會有一行寫著

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

    一般的網頁會教你說你只要在後面加個/3GB就解決了,不過我遇到的情況是:加了/3GB後開機進去電腦開始暴走!進桌面後整個不能動,然後瘋狂跳出「xxx.dll was not found」的錯誤,逼得我直接關機。幸好我的NB有另外裝個ubuntu,才得以用ubuntu進去把boot.ini修改回來,不然可能要重灌了。因此我建議要試這個方法的人不要直接將/3GB加在後面,而是另外新增一行:

    multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional (test3G) " /fastdetect /3GB /USERVA=3030

    重新開機後會進入一個開機選單,只要選有test3G的版本進去即可,萬一出現跟我一樣的問題可以重新開機然後選原本那個。而我遇到的那個問題,在/3GB後面再加個/USERVA=3030就解決了,詳情請看這裡參考資料在這裡
    修改並重開機後,我再開matlab來執行memory,此時第一項的大小從原本的1xxMB增加到981MB了!

    減少程式中無用的記憶體

    俗語說「預防勝於治療」,網官中有一篇Avoiding 'Out of Memory' Errors的文章,詳述了許多可以預先減少程式中使用的記憶體,我幫大家整理可行的方法有以下幾種,可依狀況來使用。

    a. 資料型態

    matlab在宣告變數的空間時常使用zeros函式,為了保持計算過程中的精準度預設都是用double (8-byte)來存放資料,如果你的資料不需要這麼高的精準度,可以在zeros裡多加一個classname的字串參數,可選擇的型態有 'double', 'single', 'int8', 'uint8', 'int16', 'uint16', 'int32', 'uint32', 'int64', or 'uint64'。
    如果跟我一樣要處理音訊資料,則可以在wavread後面多加一個'native'參數,如此一下,它會依照該wav檔header所紀錄的資料格式來回傳資料,如果沒用這參數的話預設是回傳 –1.0 ~ 1.0 之間的double floating point,有用的話一般是回傳int16型態,資料量會整整少了4倍

    b. S/L大法 & 擅用clear

    如果不在乎硬碟讀寫問題,或者跟我一樣有設ramdisk的話,可以使用save/load。使用的方法就是先將變數save到硬碟中,save完後clear該變數,這樣記憶體就會被釋放出來了,等到之後要用時再load回該變數即可。此外,要有保持clear暫時存放的matrix的習慣,例如在我的程式中,用wavread讀進wave資料,在做完FFT後其實就可以把原本的raw data清掉只保留FFT matrix即可。

    c. 減少測試資料

    這是最後的辦法了,原本我要測試的是40秒資料光FFT matrix就佔了300MB,在我自己的程式中還能用上述方法解決,後來要丟進去跑fastICA程式時又出現一樣的OOM問題,在懶得修改別人程式的情況下只好將測試資料減少成20秒了。。。

    後記

    Avoiding 'Out of Memory' Errors這篇文章描述的方法還滿詳盡的,雖然我覺得根本的解決辦法是裝64-bit OS & 64-bit matlab!看看那精美的8TB~~~

    6 則留言:

    匿名 提到...

    你好 我現在是碩士生 也是用MATLAB 做語音相關的題目 可以交流一下嗎? 感覺你很厲害^^

    87showmin 提到...

    當然可以,你可以直接在這裡回文或寄信給我。

    匿名 提到...

    你好~
    我已經裝win7 64bit
    matlab也是64bit
    為什麼還是出現out ot memory的問題?
    是因為跑的還是太大嗎?

    87showmin 提到...

    理論上是記憶體不足,你可以先開工作管理員監看一下matlab程式在跑的時候記憶體的使用情況。我發表這篇心得是三年前,現在的電腦配備應該隨處可見 win7 64bit / matlab 64bit / 8GB或以上的ram ,如果還是有這樣的情況,可能要檢查一下程式是否有一次性讀入太大量的圖檔。

    楊子徵 提到...

    您好,關於"加大可使用的連續記憶體"那段的"b",您給的修改boot.ini檔說明應該是windows xp適用,而win7則是修改bcdedit,但我在網路上僅找到設定成3G的說明,而沒有向您一樣,是新增一個開機選項,想請問有沒有關於win7的操作說明?
    (因為我也怕直接設定會和您一樣出問題爆走)

    謝謝

    87showmin 提到...

    我自己沒有在windows 7試過,因為後來都全面換64bit版本了,理論上現在的電腦配的作業系統應該都會是64bit。如果你怕爆走的話,記得先備份資料或者系統還原機制事先確認好再行實驗了。