解释`Rprof`的内存分析输出

时间:2019-10-05 16:16:47

标签: r memory-profiling

我正在尝试使用概要分析来查看我的代码的哪一部分对最大3GB内存的使用负责(如gc()统计的最大已使用内存see here how所述)。我正在像这样运行内存分析:

Rprof(line.profiling = TRUE, memory.profiling = TRUE)
graf(...) # ... here I run the profiled code
Rprof(NULL)
summaryRprof(lines = "both", memory = "both")

输出如下:

$by.total
                       total.time total.pct mem.total self.time self.pct
"graf"                     299.12     99.69   50814.4      0.02     0.01
#2                         299.12     99.69   50814.4      0.00     0.00
"graf.fit.laplace"         299.06     99.67   50787.2      0.00     0.00
"doTryCatch"               103.42     34.47    4339.2      0.00     0.00
"chol"                     103.42     34.47    4339.2      0.00     0.00
"tryCatch"                 103.42     34.47    4339.2      0.00     0.00
"tryCatchList"             103.42     34.47    4339.2      0.00     0.00
"tryCatchOne"              103.42     34.47    4339.2      0.00     0.00
"chol.default"             101.62     33.87    1087.0    101.62    33.87
graf.fit.laplace.R#46       85.80     28.60    3633.2      0.00     0.00
"backsolve"                 78.82     26.27    1635.2     58.40    19.46

我应该如何解释mem.total?它是什么,单位是什么?我试图查看文档?Rprof?summaryRprof,但似乎文档记录不完善:-/

编辑: Here,他们说Rprof“以固定的时间间隔探测R的总内存使用量”。但这不适合50GB,超出了我的存储能力! (现在为8GB物理+ 12 GB页面文件)。

类似地,正如R.尤达(R Yoda)指出的那样,?summaryRprof说,如果memory =“ both”,则表示“总内存的变化”。但是究竟是什么(是总内存还是总内存的变化),以及它与50GB的数字如何匹配?

编辑:在profvis中所做的相同分析-当我将鼠标悬停在50812上方时,它显示“内存分配(MB)”,并悬停在垂直于该垂直方向的黑条上行“峰值内存分配和释放的百分比”。不知道那意味着什么……这大约是50 GB,这意味着也许这可能是所有分配的总和(??)...绝对不是峰值内存使用情况:

enter image description here

1 个答案:

答案 0 :(得分:1)

?summaryRprof说:

  

如果memory =“ both”和“ both”相同,则除了计时以外,还有Mb的内存消耗。

因此mem.total以MB为单位

  

当memory =“ both”和“ both”时,报告总内存的变化(截断为零)[...]

您有8 GB的RAM + 12 GB的交换空间,但是mem.total声称您已使用50 GB?

因为它是两个后续探测之间的合计增量Rprof定期拍摄的内存使用情况快照:如果在执行函数f的同时执行了探测最后一个探测的使用量变化量已添加到f)的mem.total中。

内存使用量增量可能是负的,但我从未见过负的mem.total值,所以我猜(!)仅将正值添加到mem.total中。

这将解释您所看到的50 GB的总使用量:这不是单个时间点上分配的内存量,而是整个执行时间内的聚合内存增量。

这也说明了一个事实,gc仅显示3 GB为“已用最大(Mb)” :内存已分配和释放/重新分配了很多次,因此您无法运行这会占用大量的时间,但要花大量时间(在RAM中移动大量数据会使所有缓存失效,因此速度很慢),这是CPU应用的计算逻辑的基础。

此摘要(IMHO)似乎也掩盖了一个事实,即垃圾收集器(gc)在不确定的时间点启动,以清理释放的内存。

由于gc开始启动(不确定),因此恕我直言,将负内存增量归因于刚刚探查的单个函数是不公平的。

我会将mem.total解释为mem.total.used.during.runtime,这可能是该列的更好标签。

profvis有更详细的内存使用情况摘要(如您在问题中的屏幕快照中所示):它还汇总了负的内存使用情况变化量(释放的内存),但是profvis documentation也警告关于缺点:

  

代码面板还显示内存分配和释放。   解释此信息可能会有些棘手,因为它确实   不一定反映在那一行分配和释放的内存   代码。采样探查器记录有关内存的信息   前一个样本与当前样本之间发生的分配   一。这意味着该行上的分配/取消分配值   可能实际上是在前一行代码中发生的。

更详细的答案将需要更多的研究时间(我没有) -了解C和R源 -根据summaryRprof创建的数据文件来了解(复制)Rprof的聚合逻辑

Rprof数据文件(Rprof.out)看起来像这样:

:376447:6176258:30587312:152:1#2 "test" 1#1 "test2"

前四个数字(用冒号分隔)表示平均值(请参见?summaryRprof) -R_SmallVallocSize:R堆上小块中的向量内存[桶数] -R_LargeVallocSize:大块中的向量内存[存储桶数](来自malloc) -R堆上节点中的内存 -在该时间间隔内对内部函数duplicate的调用次数(用于复制向量,例如,在函数参数的“首次写入时复制”的情况下)

字符串是函数调用堆栈。

只有前两个数字与计算MB的当前(向量)内存使用量有关:

TotalBuckets = R_SmallVallocSize + R_LargeVallocSize
mem.used = TotalBuckets * 8 Bytes / 1024 / 1024
# 50 MB in the above `Rprof` probe line:
# (376447 + 6176258) * 8 / 1024 / 1024

有关Vcells的详细信息,请参见?Memory

顺便说一句:我想尝试summaryRProf(memory = "stats", diff = F)以获得当前的内存摘要,但是在Ubuntu上收到R3.4.4 64位错误消息:

Error in tapply(seq_len(1L), list(index = c("1::#File", "\"test2\":1#1",  : 
  arguments must have same length

您能重现吗(看起来像“统计数据”坏了)?