【R筆記】R的記憶體管理和垃圾清理

來源:互聯網
上載者:User

標籤:

R輸入命令時速度不要太快,終究是個統計軟體,不是編程!

   寫R程式的人,相信都會遇到過“cannot allocate vector of size”或者“無法分配大小為...的向量”這樣的錯誤。原因很簡單,基本都是產生一個大矩陣等對象時發生的,最乾脆的解決辦法有兩種,第一種是加大記憶體換64位系統,第二種是改變演算法避免如此大的對象。第一種辦法,是最好的辦法,不過大對象的需求是沒有止盡的,終究不是長久之道。第二種辦法是最好的思路,無論多麼大的對象都是可以弄小的,無非就是分而治之、時間換空間等,對演算法的研究也是沒有止盡的。

  升級硬體和改進演算法是解決記憶體問題的永恒的辦法,超出了本文想要表述的範圍。在這裡,只是簡單談談R語言的記憶體管理和垃圾清理機制,只有對這些有所瞭解,才能對任何問題都能找到針對性的解決辦法。

  相信所有人在遇到無法分配向量這一問題後,都能很快地找到改變“--max-mem-size”(假設都是在Windows下)或者“memory.limit”的方法,的確,這是最直接的方法。因為出現新對象無法分配記憶體的直接原因就是記憶體不夠,R擷取記憶體的方式和其他應用程式一樣,都是向作業系統要記憶體,如果無法擷取連續的某個大小的記憶體空間,就會出現無法分配記憶體的錯誤。由於大家使用R時通常都是自動安裝自動運行,作業系統願意分配給R多少記憶體都是採用的預設設定,在R中使用命令memory.size(NA)或者memory.limit()可以看到當前設定下作業系統能分配給R的最大記憶體是多少。同時可以使用memory.size(F)查看當前R已使用的記憶體,memory.size(T)查看已指派的記憶體(注意剛開始時已使用記憶體和已指派記憶體是同步增加的,但是隨著R中的垃圾被清理,已使用記憶體會減少,而已指派給R的記憶體一般不會改變。)。如果memory.limit()得到的數是一個很小的記憶體,說明作業系統太小氣了,留那麼多記憶體給別的程式用不給R。解決辦法很簡單,就是開啟R時不通過雙擊表徵圖,而是在“運行”中輸入“Rgui --max-mem-size 2Gb”(假設要分配2G記憶體且在環境變數中正確設定了R的安裝資料夾),在運行memory.limit()就會發現記憶體加大了,其實更簡單的方法是直接在R中運行memory.limit(2000),效果一模一樣,而且不用重啟R。

  可惜大多數情況下改變這個值也不會有效果,因為這個值已經足夠大,那麼無法分配記憶體的原因不是作業系統小氣對R不公,而是它確實拿不出來,誰找它要也拿不出來。這個時候就需要瞭解R的記憶體管理到底是怎麼回事了。

  R的操作基本都是通過變數來實現的,變數可以是各種各樣的物件類型,R中的對象(比如矩陣)在記憶體中存於兩種不同的地方,一種是堆記憶體(heap),其基本單元是“Vcells”,每個大小為8位元組,新來一個對象就會申請一塊空間,把值全部存在這裡,和C裡面的堆記憶體很像。第二種是地址對(cons cells),和LISP裡的cons cells道理一樣,主要用來儲存地址資訊,最小單元一般在32位系統中是28位元組、64位系統中是56位元組。在R中,可以通過ls()來查看當前所有對象名,對於每一個對象,可以通過object.size(x)來查看其佔用記憶體的大小。

  如果是因為當前對象佔用記憶體過多,那麼可以通過處理對象來擷取更大的可用記憶體。一個很有用的方法是改變對象的儲存模式,通過storage.mode(x)可以看到某個對象的儲存模式,比如某個矩陣預設就是“double”的,如果這個矩陣的數值都是整數甚至0-1,完全沒必要使用double來佔用空間,可以使用storage.mode(x) <- "integer"將其改為整數型,可以看到該對象的大小會變為原來的一半。

  對於當前對象佔用記憶體過多的情況,一個很主要的原因就是在寫程式的過程中造成了太多的中間對象,R是一個很方便的語言,大家使用它一般都是寫各種複雜的模型和演算法,很多問題構造幾個矩陣經過一系列的矩陣運算就可以很快解決,但是這些輔助演算法的大矩陣如果不清理,就會留在系統中占記憶體。因此在寫程式中對於中間對象,經常使用rm(x)是一個很好的習慣,如果是非常重要的資訊不想刪掉,可以存在硬碟裡,比如csv檔案或者RSqlite等。

  rm()用來刪除對象時,只會刪除變數的引用,並不會立即清除佔用的記憶體空間,失去引用的對象就成了記憶體中的垃圾,R清理垃圾的機制和JAVA很像,都是在一定時間內自動探索垃圾再集中清理。所以通過rm()刪除對象後在Windows的工作管理員可以看到R進程佔用的記憶體並沒有被立即釋放,而是過一段時間後才會清理。如果想要刪除的對象立刻被清理,可以運行垃圾處理函數gc(),將會立刻釋放空間。但是通常不是很必要,因為當記憶體不夠時系統會自動清理垃圾的,我們要做的只是將不再使用的對象rm()掉,在寫R程式時應該養成習慣。

  很多時候,在程式中尤其是迴圈裡,如果記憶體處理不當,還沒來得及垃圾清理,就會把記憶體撐爆,因此建立對象時一定要考慮到R的記憶體管理機制。大家都知道R中矩陣的維度並不需要賦一個固定的值(很多語言的數組長度不能為變數),這為寫程式帶來了極大的方便,因此經常在迴圈中會出現某個矩陣越來越長的情況,實際上,矩陣每增長一次,即使賦給同名的變數,都需要新開闢一塊更大的空間,假設初始矩陣為100K,第二個為101K,一直增到120K,那麼,將會分別開闢100K、101K一直到120K的連續堆記憶體,如果一開始就開一塊120K的,使之從101K逐漸增長到120K,將會大大地節約記憶體。cbind函數也是這個道理,所以在迴圈中要注意不要濫用。

  要處理好記憶體的問題其實很簡單,養成隨時關注記憶體的習慣即可,每建立一個對象或者迴圈賦值的時候適當估算一下所佔記憶體,大記憶體的中間變數用完後記得清理。如果實在需要建立一個巨大的對象,那麼就該考慮一些專門處理大記憶體對象以及平行處理的包,比如bigmemory等

來源: http://www.biostatistic.net/thread-3302-1-1.html  有人問過類似的問題:http://stackoverflow.com/questions/8342986/big-data-process-and-analysis-in-r 除了 Hadoop 以外,似乎 colbycol 包是方案之一:http://colbycol.r-forge.r-project.org/另,stackoverflow 第七章的範例:http://ishare.edu.sina.com.cn/f/23695419.html 



來自為知筆記(Wiz)



【R筆記】R的記憶體管理和垃圾清理

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.