首页 > 解决方案 > 解释“Rprof”的内存分析输出

问题描述

我正在尝试使用分析来查看我的代码的哪一部分对 3GB 内存的最大使用量负责(如gc()最大使用内存的统计所报告的,请参见此处如何)。我正在运行这样的内存分析:

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?它是什么,它的单位是什么?我试图查看文档,即?Rprofand ?summaryRprof,但似乎没有很好的文档记录:-/

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

同样,正如 R Yoda 所指出的?summaryRprof,内存 =“两者”表示“总内存的变化”。但它究竟是什么(是总内存还是总内存的变化),它与 50GB 的数字有什么关系?

编辑:进行相同的分析profvis- 当我将鼠标悬停在 50812 上时,它显示“内存分配 (MB)”,并将鼠标悬停在靠近垂直线“峰值内存分配和释放百分比”的黑条上。不知道这意味着什么......这就像 50 GB,这意味着这可能是所有分配的总和(??)......绝对不是峰值内存使用量:

在此处输入图像描述

标签: rmemory-profiling

解决方案


?summaryRprof说:

如果 memory = "both" 相同的列表,但除了计时之外,内存消耗以 Mb 为单位。

mem.totalMB也是

使用 memory = "both" 报告总内存的变化(截断为零)[...]

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

因为它是两个后续探测之间的聚合增量(定期时间间隔拍摄的内存使用快照Rprof:如果在执行函数 f 时进行探测,则将最后一次探测的内存使用增量添加到mem.totalf 中)。

内存使用增量可能是负数,但我从未见过负值mem.total,所以我猜测(!)只有正值被添加到mem.total.

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

这也解释了gc仅将 3 GB 显示为“最大使用量 (Mb)”的事实:内存被多次分配和释放/释放,这样您就不会遇到内存压力,但这会花费大量时间(移动这么多数据在 RAM 中使所有缓存无效,因此速度很慢)在 CPU 应用的计算逻辑之上。

这个总结(恕我直言)似乎也隐藏了垃圾收集器(gc)从不确定的时间点开始清理释放的内存的事实。

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

我会解释mem.totalmem.total.used.during.runtime哪个可能是该列的更好标签。

profvis有更详细的内存使用摘要(正如您在问题的屏幕截图中看到的那样):它还汇总了负内存使用增量(释放的内存),但profvis 文档也警告了缺点:

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

更详细的答案将需要更多的研究时间(我没有) - 查看 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

你能重现这个(看起来“统计”被破坏了)?


推荐阅读