【问题标题】:Memory profiling in R: how to find the place of maximum memory usage?R中的内存分析:如何找到最大内存使用的位置?
【发布时间】:2020-02-03 15:01:56
【问题描述】:

我的代码一次最多占用 3GB 内存。我用gc()弄明白了:

gc1 <- gc(reset = TRUE)
graf(...) # the code
gc2 <- gc()
cat(sprintf("mem: %.1fMb.\n", sum(gc2[,6] - gc1[,2])))
# mem: 3151.7Mb.

我猜这意味着有一次,一次分配 3151.7 MB。

我的目标是最小化在任何时候分配的最大内存。 我如何确定我的代码的哪一部分负责最大使用这 3GB 内存?即一次性分配那 3GB 的地方。

  1. 我尝试使用Rprofprofvis 进行内存分析,但是both seem to show different information(这似乎没有记录,请参阅my other question)。也许我需要将它们与不同的参数一起使用(或使用不同的工具?)。

  2. 我一直在看Rprofmem...但是:

【问题讨论】:

  • 由于Rprof 定期中断执行并获取调用堆栈快照,包括。使用的内存不够准确,无法找到导致高内存消耗的代码行(分配可能发生在中间,内存在“不可预测”的时间被 gc 释放)
  • 您是否尝试过使用Rprofmem 在内存分配发生时跟踪它们(不是间隔快照)?见cran.r-project.org/doc/manuals/…
  • @RYoda 是的,我一直在查看 Rprofmem... 但是 1) in the profmem vignette 他们写道:“使用 utils::Rprofmem() 无法量化总内存使用量给定时间,因为它只记录分配,因此不反映垃圾收集器完成的释放。” 2)Rprofmem的结果如何输出?这个来源不言自明:"Summary functions for this output are still being designed"
  • 很好的发现,R 对最终用户来说(还)不是非常支持。恕我直言Rprofmem 是查找代码行的好方法,这些代码行(重复)分配内存会导致程序执行缓慢(在这种情况下,当前分配的总内存是次要的)。不过,我从未尝试过聚合输出(是否有任何软件包?)恕我直言,如果我想找到 gc 无法释放的内存泄漏,释放是“唯一”重要的。
  • @RYoda yes :-) 但它来自 github 的最新版本:install_github('goldingn/GRaF')。对不起,我仍然没有时间看你的详细答案,希望明天!

标签: r memory-profiling


【解决方案1】:

我的代码一次最多占用 3GB 内存。

虽然看起来您的代码通过调用一个函数一次消耗了大量 RAM,但您可以通过使用 RStudio 的内置分析查看函数(及其子调用)的实现细节来分解内存消耗(基于profvis)查看执行时间和粗略的内存消耗。例如。如果我使用我的演示代码:

  # graf code taken from the tutorial at
  # https://rawgit.com/goldingn/intecol2013/master/tutorial/graf_workshop.html
  library(dismo)  # install.packages("dismo")
  library(GRaF)   # install_github('goldingn/GRaF')

  data(Anguilla_train)

  # loop to call the code under test several times to get better profiling results
  for (i in 1:5) {

    # keep the first n records of SegSumT, SegTSeas and Method as covariates
    covs <- Anguilla_train[, c("SegSumT", "SegTSeas", "Method")]

    # use the presence/absence status to fit a simple model
    m1 <- graf(Anguilla_train$Angaus, covs)
  }

使用 Profile > Start Profiling 菜单项开始分析,获取上述代码并通过上述菜单停止分析。

Profile > Stop Profiling RStudio 将结果显示为火焰图,但您要查找的内容隐藏在配置文件结果的 Data 选项卡中(我已经展开所有显示大量内存消耗的函数调用):

memory 列中的数字表示为每个调用函数分配的内存(正数)和释放的内存(负数),其值应包括整个子调用树的总和 + 函数中直接使用的内存。

我的目标是最小化在任何时候分配的最大内存。

你为什么要这样做?您是内存不足还是您怀疑重复的内存分配导致执行时间过长?

高内存消耗(或重复分配/解除分配)通常伴随着缓慢的执行性能,因为复制内存需要时间。

因此,请根据您的优化目标查看MemoryTime 列,以找到具有高值的函数调用。

如果您查看 GRaF 包的源代码,您可以在 graf.fit.laplace 函数中找到一个循环(最多 50 次“牛顿迭代”),它调用“慢”R 内部函数,如 cholbacksolveforwardsolve 以及包本身实现的慢速函数(如 cov.SE.d1)。

现在您可以尝试为这些函数找到更快(或内存消耗更少)的替代品...(抱歉,我无能为力)。

PS:profvis 在内部使用Rprof,因此通过定期探测当前内存消耗并为当前活动函数(调用堆栈)计数来收集分析数据。

Rprof 有局限性(主要不是精确的分析结果,因为垃圾收集器在不确定的时间触发,并且释放的内存归因于下一个探测间隔中断停止的函数,它确实不是 通过绕过 R 的内存管理 API 的 C/C++ 代码/库识别直接从操作系统分配的内存)。 它仍然是内存和性能问题的最简单且通常足够好的指示...

有关profvis 的介绍,请参阅:https://rstudio.github.io/profvis/

【讨论】:

  • 感谢您的努力!但是我觉得您完全绕过了实际问题(我用粗体表示)并且您继续扩展显示我已经提到的不是我想要的统计数据和工具,因为它们更像是营业额而不是一次分配的最大值.不管怎么说,还是要谢谢你。最后我解决了它手动逐行运行代码并查看gc()报告的最大内存使用统计数据。
  • 感谢您的诚实反馈!我很高兴听到您无论如何都能解决问题。也许将来有人会提供更好的答案,以避免像您必须做的那样大量的手动工作。
猜你喜欢
  • 1970-01-01
  • 2023-03-20
  • 1970-01-01
  • 1970-01-01
  • 2014-08-26
  • 2017-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多