Android统计方法耗时之:内存控制

鸽了好久, 如今补上缓存


上篇提到, 作好方法堆栈的收集后, 项目工程运行不到两分钟, 出先卡顿, 直至完全卡死.markdown

经过Android Studio Profile调查得知, 正是我统计耗时的MethodNode堆栈撑爆了内存.app

为了监控方法耗时, 可是居然搞出了内存问题, 有些搞头..spa

缘由调查

由于每一个方法都被插桩, 因此每一个方法的先后调用关系都作成MethodNode被存到了堆栈中,设计

因此随着使用时间的增加, 全部方法关系都存进了堆栈中, 不被清理, 就撑爆了内存.code

设计方案

这个问题其实是个OOM问题. OOM从技术角度看, 是由于改释放的内存不被释放.orm

可是要解决OOM问题, 却须要从具体业务入手, 由于只有经过业务关系梳理, 才知道那些内存应该释放.对象

针对此次的问题, 就是要减小方法关系的存储.内存

因此作以下设计:

  1. 过滤掉重复的方法调用关系MethodNode. 只保存精简方法关系堆栈
  2. 制做MethodNode缓存池, 建立MethodNode时, 优先从缓存池中获取. 获取失败再建立
  3. 每一个被配断定为重复的方法对象MethodNode, 存入缓存池等待复用
方案设计好, 又面临以下问题:
  1. 如何判断"重复的调用关系"?
  2. 缓存池要频繁读写, 如何设计避免读写冲突?

1. 重复调用关系判断

由于MethodNode中保存了父节点和子节点信息. 因此当获得一个新MethodNode时,开发

获取它的父节点信息, 再从现有的堆栈中, 找到对应的父节点,

查看该父节点中的全部子节点是否已经包含那个新MethodNode的信息.

若是包含, 说明重复, 则丢弃这个新MethodNode. 若是不包含, 就把新MethodNode加入堆栈里父节点的子节点列表里,

若是没有找到父节点, 则这个新MethodNode直接当作root级别父节点, 存入堆栈

2. 缓存池设计

聊这个, 我可就不困了.

特别为这个设计里一个存取交换池.

简单的说, 设计了两个缓存池, 某个时间段内, 一个池只取, 另外一个池只存.

当"只取"的池子空了, 就切换成"只存"状态. 同时, 以前"只存"的池子同步切换为"只取"

这样两个池子, 交替使用

若是两个坑都没有砖, 我就去找砖厂要砖. 回收的砖一样按照轮换扔到当前应该回收转的坑里.

至关于作到存取隔离, 也就没有了存取冲突. 同时有复用机制. 内存的数量不会激增.

过程大体以下:

结果验证

按照设计, 开发完毕实测.

缓存池初期不断增大, 2w个以后逐渐稳定.再也不增加.

知足了整个app的循环复用. 内存问题解决.

相关文章
相关标签/搜索