单细胞36计之29---错误:无法分配大小为6.9Gb的矢量

29、第二十九计 树上开花
比喻将本求利,别人收获。
此计是说借助某种局面(或手段)布成有利的阵势,兵力弱小但可使阵势显出强大的样子或者是弱小的部队通过凭借某种因素,改变外部形态之后,自己阵容显得充实强大了。

群里看到一个问题

image.png

一般是内存不够了,可以试试

options(future.globals.maxSize = 1000 * 1024^3)

不想知道原理的话,可直接看文末的终极解决办法

写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程序时应该养成习惯。如图

image.png

很多时候,在程序中尤其是循环里,如果内存处理不当,还没来得及垃圾清理,就会把内存撑爆,因此新建对象时一定要考虑到R的内存管理机制。大家都知道R中矩阵的维度并不需要赋一个固定的值(很多语言的数组长度不能为变量),这为写程序带来了极大的方便,因此经常在循环中会出现某个矩阵越来越长的情况,实际上,矩阵每增长一次,即使赋给同名的变量,都需要新开辟一块更大的空间,假设初始矩阵为100K,第二个为101K,一直增到120K,那么,将会分别开辟100K、101K一直到120K的连续堆内存,如果一开始就开一块120K的,使之从101K逐渐增长到120K,将会大大地节约内存。cbind函数也是这个道理,所以在循环中要注意不要滥用。

要处理好内存的问题其实很简单,养成随时关注内存的习惯即可,每新建一个对象或者循环赋值的时候适当估算一下所占内存,大内存的中间变量用完后记得清理。如果实在需要新建一个巨大的对象,那么就该考虑一些专门处理大内存对象以及并行处理的包,比如bigmemory等。

总而言之,如果实在什么原理都不想知道,出现了标题中的问题的时候,就直接运行图中代码

image.png

如果这样都解决不了,就换台电脑吧

欢迎大家补充和扩展:
参考链接:https://www.dxy.cn/bbs/newweb/pc/post/44027389

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,029评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,238评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,576评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,214评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,324评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,392评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,416评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,196评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,631评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,919评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,090评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,767评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,410评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,090评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,328评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,952评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,979评论 2 351