由于 native 内存分配的频率过高,获取 Java 层堆栈又比较耗时,在拦截 native 内存分配时并不适合直接频繁抓取 Java 堆栈。Native 内存不同于 Java 内存,单从拦截到的数据很难直观给出结论。通常对于内存等资源不合理使用导致的资源不足而引发的问题都很难归因,从拦截到的数据来看,CameraMetaData 所引用的内存最大,嫌疑也最大,基于此决定剖析一下这个问题
分析 native 内存的分配和释放
通过拦截到的堆栈可以看出,CameraMetaData 的创建堆栈的上层是 Java 调用,最终在 native 层进行的内存分配(boot-framework.oat & libandroid_runtime.so)。CameraMetaData 对象有两部分内存,对象本身 & mBuffer 指向的 camera_metadata_t 所引用的内存;通过源码可知,每个 CameraMetadata 对象的 mBuffer 所指向的 camera_metadata_t 是独立的,彼此是不重叠的。
既然工具能拦截到这么多的未释放的内存分配,一定是因为这些内存的释放逻辑出问题导致的,我们需要优先调查清楚 CameraMetadata.mBuffer 的释放逻辑。通过分析 CameraMetadata.cpp 的源码可知,CameraMetadata::release()并未释放 mBuffer 所指向的内存,而是把 mBuffer 所指向的内存赋值给了另一个 CameraMetadata 对象;CameraMetadata::clear()是真释放,而 clear 的调用有两个场景:一个是在 camera_metadata_t 复用时,另一个是 CameraMetadata 对象析构时。