前言
最近公司的应用需要接入人脸识别功能,经过筛选,选择了虹软的人脸识别SDK。本文以虹软android SDK 3.0版本为基础,记录一下卡顿的解决过程,这里先感谢一下虹软的工程师,在解决的过程中帮了我很多忙。
问题
下载虹软官方demo测试,使用手机摄像头进行人脸识别,在人脸超过20人时,移动手机,相机有明显的卡顿的现象。
分析
卡顿的原因一般有如下可能:
- 主线程任务过多,阻塞导致卡顿
- CPU中任务过多,影响了主线程
- 内存抖动严重,频繁的gc
对以上原因一一分析:
- demo中调用人脸识别的方法是在主线程中进行的,人脸少的时候,不存在卡顿现象,人脸多的时候,卡顿现象出现。猜测可能和人脸识别中的方法有关,人脸过多时导致人脸追踪耗时增加,从而引起了卡顿。
- 通过命令行监控手机CPU的使用现象,在人脸少与人脸多的情况下都是20%左右,CPU并没有占用过多,所以这里不是导致卡顿的原因。
- 通过检测人脸识别时的log,应用程序并没有频繁的gc,所以这里也不是导致卡顿的现象。
经过以上的分析,总结一下,卡顿的原因是因为人脸过多时导致人脸追踪耗时增加而导致的,所以我们从这个方法入手想解决方案。
解决方案
既然是因为主线程的任务过多,阻塞导致了卡顿,那太简单了,我们把人脸识别的方法放在线程里面跑不就行了吗,so easy!!!修改代码后再次运行,卡顿现象消失了。
但是新的问题又出现了,人脸框一直在闪烁,体验非常不好。经过分析代码,发现之前的demo中程序是这么走的:
- 清除人脸框的操作
- 进行人脸识别
- 绘制新的人脸框
这样操作在主线程中没有问题,但是我们现在把人脸识别放在了子线程中运行,这样就导致了在清除人脸框后,没有及时绘制新的人脸框,导致了闪烁的现象出现。所以这里我们把清除人脸框的操作放在绘制新的人脸框之前来做:
- 先在子线程中进行人脸识别
- 回到主线程中,清除人脸框
- 绘制新的人脸框
修改后测试,闪烁问题修复了。
但是但是又有新问题出现了,人脸识别长时间后程序会异常闪退,经过分析log,是oom,我们现在来分析解决下oom的问题。
OOM分析
由于相机视频数据帧一直不断在向线程池中添加新的的任务,时间长了,来不及处理这些任务,就会导致内存溢出。因此我们这里选择线程池的执行策略,当任务队列满时,扔掉最先进入队列的任务,这样就不会导致内存溢出。贴段代码:
int corePoolSize = 1;
int maxPoolSize = 1;
long keepAliveTime = 5;
BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>(10);
//拒绝策略1:将抛出 RejectedExecutionException.
RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardPolicy();
ThreadPoolExecutor executor;
private void initExecutor(){
executor = new ThreadPoolExecutor
(corePoolSize, maxPoolSize,
keepAliveTime, TimeUnit.SECONDS,
queue, handler);
}
这里线程池中只有一个线程在处理人脸识别,任务队列我这里设置的10个,超出时就会抛出。经过测试,解决了oom的问题。
以上就是这次虹软人脸识别sdk中卡顿优化过程。有任何错误,欢迎大家指正。