如何在 Rust 中调试内存问题? [英] How do I debug a memory issue in Rust?

查看:233
本文介绍了如何在 Rust 中调试内存问题?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望这个问题不要太开放.我遇到了 Rust 的内存问题,在那里我通过调用 next 得到了内存不足"Iterator trait 对象.我不确定如何调试它.打印只是让我到了发生故障的地步.我对其他工具不是很熟悉,例如 ltrace,所以虽然我可以创建跟踪(231MiB,pff),但我真的不知道如何处理它.这样的痕迹有用吗?我会更好地抓住 gdb/lldb 吗?还是 Valgrind?

I hope this question isn't too open-ended. I ran into a memory issue with Rust, where I got an "out of memory" from calling next on an Iterator trait object. I'm unsure how to debug it. Prints have only brought me to the point where the failure occurs. I'm not very familiar with other tools such as ltrace, so although I could create a trace (231MiB, pff), I didn't really know what to do with it. Is a trace like that useful? Would I do better to grab gdb/lldb? Or Valgrind?

推荐答案

总的来说,我会尝试以下方法:

In general I would try to do the following approach:

  1. 减少样板文件:尝试缩小 OOM 问题的范围,这样您就不会拥有太多额外的代码.换句话说:你的程序崩溃得越快越好.有时也可以撕下特定的代码段并将其放入额外的二进制文件中,仅用于调查.

  1. Boilerplate reduction: Try to narrow down the problem of the OOM, so that you don't have too much additional code around. In other words: the quicker your program crashes, the better. Sometimes it is also possible to rip out a specific piece of code and put it into an extra binary, just for the investigation.

减少问题大小:将问题从 OOM 降低到简单的内存过多",这样您就可以实际告诉某些部分浪费了一些东西,但不会导致 OOM.如果很难判断您是否看到了问题,您可以降低内存限制.在 Linux 上,这可以使用 ulimit 来完成:

Problem size reduction: Lower the problem from OOM to a simple "too much memory" so that you can actually tell the some part wastes something but that it does not lead to an OOM. If it is too hard to tell wether you see the issue or not, you can lower the memory limit. On Linux, this can be done using ulimit:

ulimit -Sv 500000  # that's 500MB
./path/to/exe --foo

  • 信息收集:如果您的问题足够小,您就可以收集噪声级别较低的信息.您可以尝试多种方法.请记住使用调试符号编译您的程序.关闭优化也可能是一个优势,因为这通常会导致信息丢失.两者都可以通过在编译期间不使用 --release 标志来存档.

  • Information gathering: If you problem is small enough, you are ready to collect information which has a lower noise level. There are multiple ways which you can try. Just remember to compile your program with debug symbols. Also it might be an advantage to turn off optimization since this usually leads to information loss. Both can be archived by NOT using the --release flag during compilation.

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

    这向您展示了一个图表,它象征着程序的哪些部分占用了多少内存.有关详细信息,请参阅官方文档.

    This shows you a graph which symbolizes which parts of your program eat which amount of memory. See official docs for more details.

    rr: 有时很难弄清楚实际发生了什么,尤其是在您创建了个人资料之后.假设您在第 2 步中做得很好,您可以使用 rr:

    rr: Sometimes it's very hard to figure out what is actually happening, especially after you created a profile. Assuming you did a good job in step 2, you can use rr:

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

    这将产生一个具有超能力的 GDB.与普通调试会话的区别在于,您不仅可以continue,还可以reverse-continue.基本上,您的程序是从录音中执行的,您可以在其中根据需要来回跳转.这个维基页面为您提供了一些额外的例子.需要指出的一件事是 rr 似乎只适用于 GDB.

    This will spawn a GDB with superpowers. The difference to a normal debug session is that you can not only continue but also reverse-continue. Basically your program is executed from a recording where you can jump back and forth as you want. This wiki page provides you some additional examples. One thing to point out is that rr only seems to work with GDB.

    很好的旧式调试:有时您会得到仍然太大的跟踪和记录.在这种情况下,您可以(结合 ulimit 技巧)使用 GDB 并等待程序崩溃:

    Good old debugging: Sometimes you get traces and recordings that are still way too large. In that case you can (in combination with the ulimit trick) just use GDB and wait until the program crashes:

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

    您现在应该获得一个正常的调试会话,您可以在其中检查程序的当前状态.GDB 也可以使用核心转储启动.这种方法的普遍问题是你不能回到过去,也不能继续执行.因此,您只能看到当前状态,包括所有堆栈帧和变量.如果需要,您也可以在这里使用 LLDB.

    You now should get a normal debugging session where you can examine what the current state of the program was. GDB can also be launched with coredumps. The general problem with that approach is that you cannot go back in time and you cannot continue with execution. So you only see the current state including all stack frames and variables. Here you could also use LLDB if you want.

    (潜在)修复 + 重复:在确定可能出错的地方后,您可以尝试更改代码.然后再试一次.如果仍然无法正常工作,请返回第 3 步并重试.

    (Potential) fix + repeat: After you have a glue what might go wrong you can try to change your code. Then try again. If it's still not working, go back to step 3 and try again.

    这篇关于如何在 Rust 中调试内存问题?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆