筆記:
一、R輸入命令時速度不要太快,終究是個統計軟件,不是編程!
二、memory.limit()查看當前操做系統分配內存給R的最大限
度(單位是M?)
三、要常常 rm(object) 或者 rm(list=ls()) 和 gc()釋放內存空間
四、儘可能提早設置矩陣大小固定不變,矩陣
每增加一次,即便賦給同名的變量,都須要新開闢一塊更大的空間
五、儘可能避免循環語句
六、用矩陣,而不是數據框
七、在大數據集運行前如今子數據集上測試程序
八、將數據保存到R的住內存以外的包:
biglm和speedglm包能以高效的形式實現大型數據的線性模型擬合和廣義線性模型擬合
分析bigmemory包生成的矩陣:
- biganalytics包提供k均值聚類、列統計和一個biglm的封裝
- bigtabulate提供了table()\split()和tapply()功能
- bigalgebra包提供了高級的線性代數函數
biglar包跟ff配合使用,爲在內存中沒法放至的大數據提供了最小角迴歸,lasso和逐步迴歸分析。
Borbdingnag包能夠處理大數字(大於2的1024次方的數)
寫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
等