购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

2.2.2 获取Native堆栈

当自定义函数检测到异常的内存申请后,我们就需要获取堆栈来帮助定位问题了。在Java代码中,只需要调用Debug.DumpHeap方法就能获取当前Java函数的堆栈,而Native中没有直接获取堆栈的方法,需要我们自己去实现。这里介绍一种通过CFI(Call Frame Information,调用帧信息)获取Native堆栈的方案,这是目前在Android系统中使用得最普遍的方案,比如Native Crash输出的堆栈、Android官方的一些Native调试工具等采用的都是这种方案。

在程序运行时,当Native函数执行进入栈的指令后,就会将对应指令的地址等信息写入.eh_frame和.eh_frame_hdr段。这两个段也属于so这个ELF文件中的段,因此,想要获取Native的堆栈,只需要读取这两个段中的数据。

在实际项目中,并不需要我们自己来实现这个方案,Android系统中可以直接使用libunwind库来获取Native的堆栈信息,但libunwind库实际上是通过读取CFI来实现的。libunwind库的用法如下面代码所示,其中_Unwind_Backtrace函数就是libunwind库所提供的用于获取堆栈信息的函数,该函数的入参需要传入一个回调函数和一个指针数据。其中,回调函数可以获取_Unwind_Backtrace函数在栈回溯过程中回调的数据,并且可以控制是否要继续进行栈回溯。指针数据则可以传入自定义的BacktraceState结构体,用于存储回调的数据以及限制最大栈回溯深度。

当我们把自定义的回调函数unwindCallback传入_Unwind_Backtrace方法后,就能在回调函数中接收回调过来的数据了,此时便可以把栈帧的地址取出来,并存储到前面传入的BacktraceState结构体的buffer容器中。如果缓存的栈的深度大于前面配置的阈值30,则返回_URC_END_OF_STACK来退出栈的回溯,其他情况下则返回_URC_NO_REASON,表示继续回溯,代码如下。

如果堆栈的信息已经缓存到buffer容器中,我们就可以将堆栈信息打印出来,代码如下所示。 TfHvdD1ca115UYReLFU5qcvVuOR1JwR5WWlvyyG3B/lfHdbVqXCtrNmi2gkpXB1Z

点击中间区域
呼出菜单
上一章
目录
下一章
×