2016-07-07 82 views
5

我希望这个问题不是太开放。我遇到了Rust的内存问题,我在那里得到了an "out of memory" from calling next on an Iterator trait object。我不确定如何调试它。打印只会让我发生故障。我对ltrace等其他工具并不是很熟悉,所以尽管我可以创建一个跟踪(231MiB,pff),但我并不知道如何处理它。这样的痕迹有用吗?我会更好地抓住gdb/lldb吗?还是Valgrind?如何在Rust中调试内存问题?

+0

Valgrind总是一个好的开始。尝试优化您的代码。 –

+2

@EliSadoff如何优化我的代码有助于调试内存问题? – Apanatshka

回答

3

一般来说我会试着做下面的办法:

  1. 样板减少:尽量缩小OOM的问题,让您不必四处太多额外的代码。换句话说:程序崩溃越快,效果越好。有时候也可以将特定的一段代码翻译成一个额外的二进制代码,仅供调查。

  2. 问题尺寸缩小:下从OOM简单的“过多的内存”,让你可以真正说出一些部分废物的东西,但它不会导致OOM问题。如果很难分辨出是否存在问题,则可以降低内存限制。在Linux上,这可以使用ulimit做到:

    ulimit -Sv 500000 # that's 500MB 
    ./path/to/exe --foo 
    
  3. 信息收集:如果你的问题是足够小,你就可以收集具有较低的噪音水平的信息。有多种方法可以尝试。只要记住用调试符号编译你的程序。此外,关闭优化可能是一个优势,因为这通常会导致信息丢失。两者都可以通过在编译期间不使用--release标志进行归档。

    • 堆纹:一种方法是使用过gperftools

      LD_PRELOAD="/usr/lib/libtcmalloc.so" HEAPPROFILE=/tmp/profile ./path/to/exe --foo 
      pprof --gv ./path/to/exe /tmp/profile/profile.0100.heap 
      

      这说明你这象征着你的程序的部分吃内存,并且量的曲线图。有关更多详细信息,请参见official docs

    • rr:有时很难找出实际发生的情况,尤其是在创建配置文件后。假设你没有在步骤2中的好工作,你可以使用rr

      rr record ./path/to/exe --foo 
      rr replay 
      

      这将产生一个GDB与超级大国。与普通调试会话的区别在于,您不仅可以使用continue,还可以使用reverse-continue。基本上你的程序是从录音中执行的,你可以随意来回跳动。 This wiki page为您提供了一些额外的例子。有一点需要指出的是,rr似乎只适用于GDB。

    • 良好的旧调试:有时你会得到痕迹和记录仍然太大。在这种情况下,你可以(与ulimit招组合)只使用GDB,等到程序崩溃:

      gdb --args ./path/to/exe --foo 
      

      您现在应该得到正常的调试会话,你可以检查一下程序的当前状态为。 GDB也可以用coredumps启动。这种方法的一般问题是,你不能回到过去,你不能继续执行。所以你只能看到当前状态,包括所有的栈帧和变量。如果你愿意的话,你也可以使用LLDB。

  4. (潜在的)固定+重复:后你有胶水什么可能出错,你可以试着改变你的代码。然后再试一次。如果仍然无法使用,请返回步骤3并重试。

1

通常,为了调试,您可以使用基于日志的方法(通过自己插入日志或使用诸如ltraceptrace等工具为您生成日志),也可以使用使用调试器。

请注意,ltraceptrace或基于调试器的方法要求您能够重现问题;我倾向于支持手动日志,因为我在一个行业工作,那里的bug报告通常太不精确,无法立即复制(因此我们使用日志创建复制器场景)。

Rust支持这两种方法,而用于C或C++程序的标准工具集适用于它。

我个人的做法是让进行一些的日志记录以快速缩小发生问题的位置,并且如果日志记录不足以激发调试器以进行更精细的检查。在这种情况下,我会建议直接调试器。

将生成一个panic,这意味着通过中断对恐慌钩子的调用,您可以在出现错误时看到调用堆栈和内存状态。

用调试器启动程序,在恐慌钩上设置一个断点,运行程序,获利。