之前提了[[124-R编程18-R的内部机制2]],通过复制修改机制,R 非常聪明在合适的时机建立副本,节省了不必要的内存开支。
这里我们来进一步拓展一下相关知识。
用lobstr包的obj_size()函数可以求变量的存储大小, 如obj_size(x), 也可以求若干个变量的总大小, 如obj_size(x,y)。
因为各种绑定到同一对象的可能性, 所以变量的存储大小可能会比想象要少, 比如, 共用若干列的两个数据框, 字符型向量, 等等。基本R软件的object.size()则不去检查是否有共享对象, 所以对列表等变量的存储大小估计可能会偏高。
> x <- matrix(1:10000)
> object.size(x)
40216 bytes
> lobstr::obj_size(x)
40,216 B
> y <- list(x,x,x)
> lobstr::obj_size(y)
40,296 B
> object.size(y)
120728 bytes
这个原因你还记得吗?
此外,还有一些实用函数。
> lobstr::ref(y,y1)
o [1:0x7fd896f93558] <list>
+-[2:0x7fd89809f840] <dbl>
+-[3:0x7fd89809f878] <dbl>
\-[4:0x7fd89809f8b0] <dbl>
o [5:0x7fd896eec6e8] <list>
+-[6:0x7fd897d9f088] <dbl>
+-[7:0x7fd897d9f0c0] <dbl>
\-[8:0x7fd897d9f0f8] <dbl>
lobstr::mem_used()
返回当前使用的内存大小:
> lobstr::mem_used()
430,635,640 B
但是其也存在一定的问题:
在当前的R语言中, 一个对象的引用(如绑定的变量名)个数, 只区分0个、1个或多个这三种情况。当内存中的对象没有变量引用的时候,R 就会定期启动垃圾回收(garbage collector, GC)。
rm(x)
只是删除绑定, 并不会马上清除x绑定的对象。如果已经有多个引用, 即使是只有2个, 减少一个引用也还是“多个”状态, 不会变成1个。
垃圾收集器是在R程序要求分配新的对象空间时自动运行的, R函数gc()
可以要求马上运行垃圾收集器, 并返回当前程序所用的存储量;lobstr包的mem_used()
函数则报告当前会话内存字节数。
比如下面的例子:
R 并不会完整保存序列的全部内容,其仅仅保留开头与结尾的数字。
所以上面几个向量的内存大小才是相同的。
[1]
09. 工作空间和变量赋值 · 语雀 (yuque.com): https://www.yuque.com/mugpeng/rr/ebhayr
[2]
2. 标示符和值 · 语雀 (yuque.com): https://www.yuque.com/mugpeng/rr/xhuxd3