批量导出dump文件中的Bitmap
上一篇文章提到了查看memory dump文件中的Bitmap对象相应的图像,进一步我们可以批量的将dump文件中所有的Bitmap对象转化为png格式的图像文件。MAT不仅提供了一组Eclipse extension points,还提供了从dump文件读取数据的API。利用MAT提供的API,我们可以写一个Java程序批量导出dump文件中所有的Bitmap。
MAT扩展API接口
利用ISnapshot接口可以从heap dump中解析数据,ISnapshot代表了整个heap dump,提供了各种方法从中读取object和class,获取objects的大小等。我们可以通过SnapshotFactory获取ISnapshot实例。IObject接口代表一个Java对象,IClass,IInstance和IArray都继承了IObject。IClass代表class对象,可通过getObjectIds()方法获得该class的所有实例ID。IInstance代表非array对象,可通过resloveValue()方法获得成员变量的值。IArray代表array对象,分为IPrimitiveArray和IObjectArray,可分别通过getValueArray()方法获得primitive array值或getReferenceArray()方法获得address array。
上述层次对象模型很直观并容易理解,但由于heap dump文件中有时会有非常多的对象,MAT不在ISnapshot实例中保存整个层次模型,而是为每个对象分配一个ID,并利用ID为索引从ISnapshot接口获得对象的具体信息,如class,size,referenced objects等。大都需要遍历对象的计算量大的工作都是通过对象ID而不是层次模型来实现,比如计算retained size,path to GC root等。只有当需要获得一个object的所有信息时,比如成员变量名称和变量值,才需要利用层次对象模型里的各种类。我们可以通过mapIdToAddress()和mapAddressToId()方式实现对象的ID和地址的互相转换。
android bitmap导出工具实现
首先需要获得MAT源码的核心模块,可以从MAT SVN repository下载全部源码并提取核心部分,或者直接参考ekabanov或joebowbeer项目,这两个项目已经将MAT源码核心模块抽取出来,只要修改自定义的部分就可以了。
下面给出从dump文件批量导出bitmap的源码。基本思路如下:
- 通过SnapshotFactory获得与dump文件对应的ISnapshot对象
- 通过类名android.graphics.Bitmap获得IClass对象
- 通过IClass的getObjectIds()方法获得所有Bitmap对象ID集合
- 通过ISnapshot的getObject()方法获得与Bitmap对象ID对应的IObject对象
- 通过IObject的resloveValue()方法获得Bitmap对象的mHeight,mWidth和mBuffer成员变量值
- 调用Java的BufferedImage,ImageIO等API将获得的数据保存为png文件
|
|
编译后得到dump_android_bitmap.jar,通过如下命名即可将file.hprof文件中所有的bitmap对象导出为png格式图像文件
|
|
可以用Bitmap对象的地址作为文件名的一部分,以方便反查某一图像在MAT中对应的对象,并分析该对象的引用链。可以利用MAT提供的OQL(Object Query Language)查询dump文件中某个类的所有实例,或根据对象地址查询某个对象实例。
- 查询所有mBuffer不为空的Bitmap对象
|
|
- 查询特定对象地址对应的对象实例
|
|
参考
http://www.slideshare.net/AJohnson1/extending-eclipse-memory-analyzer
https://wiki.eclipse.org/MemoryAnalyzer/Reading_Data_from_Heap_Dumps