为什么 Android 应用程序使用的本机共享库的调试速度很慢?
我经常使用 gdbServer 来调试远程 Android 应用程序。我设置断点的区域是一个共享库,用 C++ 编写。
单步执行代码非常慢。有谁知道这是为什么?我的假设是对库的 JNI 调用会造成很大的延迟。
I am frequently using gdbServer to debug a remote Android application. The area I have set breakpoints in is a shared library, written in c++.
Stepping through the code is extremely slow. Does anyone know why this is? My assumption is that the JNI calls to the library impose a large delay.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
当您处于断点处,并在 GDB 中执行
step
命令时,实际上没有发生任何 JNI 调用(您已经处于本机代码中,只需继续直到下一行,或单步进入下一个函数,什么是JNI 与它有关吗?)不幸的是,即使在本机执行时,
step
也可能很慢;对于优化的代码尤其如此。step
命令如何工作?理论上,GDB可以检查当前行的指令,发现没有CALL
和JMP
,并设置下一行第一条指令的临时中断,并继续。这会很快,但 GDB 实际工作原理并非如此。相反,它所做的事情更简单:它单步执行处理器,并在每条指令处询问“我现在停止在上次停止的同一行上吗?”。如果“是”,则再次单步执行,直到答案为“否”。您可以通过设置
set debug infrun 1
来观察此行为。根据当前行的指令数量,可能需要 100 个单步才能完成
step
命令。对于本机调试来说,这可能会很慢,当使用远程 gdbserver 时,它可能会变得更慢,因为每次单步完成时,GDB 都需要询问 gdbserver“我现在在哪里”。 GDB 和 gdbserver 之间有大量数据包传输。您可以使用set debug remote 1
观察这些数据包。的因素
步骤
可能涉及其中的 100 个因素产生您观察到的非常慢的
step
执行。一种可能的解决方法是避免执行
步骤
。相反,设置断点,并检查每个断点的程序状态。最终您将到达错误“下游”的断点(即程序已经处于错误状态)。现在在其“上游”某处设置一个新断点,然后查看那里的状态。使用“分而治之”的方法,您很快就会将问题归零。When you are at a breakpoint, and execute
step
command in GDB, no JNI calls are actually happening (you are already in native code, and just continue until next line, or step into the next function, what's JNI got to do with it?)Unfortunately,
step
could be slow even when executing natively; especially so for optimized code.How could
step
command work? In theory, GDB could examine instructions for the current line, discover that there are noCALL
s andJMP
s, set a temporary break of the first instruction on the next line, and continue. That would be fast, but that's not how GDB actually works.What it does instead is something simpler: it single-steps the processor, and at each instruction asks "am I now stopped on the same line I was last time I stopped?". If "yes", single-step again, until the answer is "no". You can observe this behavior by setting
set debug infrun 1
.Depending on how many instructions your current line has, it could take a 100 single-steps to complete your
step
command. That can be slow with native debugging, it can become much slower still when using remote gdbserver, as every time single-step completes, GDB needs to ask gdbserver "where am I now". That's a lot of packets flying between GDB and gdbserver. You can observe these packets withset debug remote 1
.Thus the factors that
step
may involve a 100 of thesecombine to produce the very slow
step
executions you've observed.A possible workaround is to avoid doing
step
s. Instead, set breakpoints, and examine program state at each. Eventually you'll get to a breakpoint that is "downstream" from the bug (i.e. the program is already in a bad state). Now set a new breakpoint somewhere "upstream" from that, and look at the state there. Using "divide and conquer" approach, you'll pretty soon zero in on the problem.