利用自定义线程池解决OOM问题
从Camera获取到了byte[]类型的图像数据之后,需要送到so库中,让so库进行相应的处理,并对其处理的结果进行相应的反馈;1s大概有30帧的数据,但是除去一些装载数据的事件,时间就变大了,实际可拿到的帧率就变小了;在此每秒取5帧,每张图片大致1~3M。这大致就是解决这个问题的背景框架。起因处理
从Camera获取到了byte[]类型的图像数据之后,需要送到so库中,让so库进行相应的处理,并对其处理的结果进行相应的反馈;1s大概有30帧的数据,但是除去一些装载数据的事件,时间就变大了,实际可拿到的帧率就变小了;在此每秒取5帧,每张图片大致1~3M。这大致就是解决这个问题的背景框架。
起因
处理图片时,耗时较长,放在主线程中,会造成卡顿,严重的时候会造成ANR。但是算法库处理时,会依赖于上一帧的数据,所以还是要按照顺序,一帧一帧来处理。 从Camera取数据后,立即开启线程处理的代码如下:
//取数据
mCamera.addCallbackBuffer(new byte[size.width * size.height * ImageFormat.getBitsPerPixel(ImageFormat.NV21) / 8]);
mCamera.setPreviewCallbackWithBuffer(new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
if (mCallback != null && mCamera != null){
// 处理数据回调
mCallback.onImageAvaliable(data, size.width, size.height);
mCamera.addCallbackBuffer(new byte[size.width * size.height * ImageFormat.getBitsPerPixel(ImageFormat.NV21) / 8]);
}
}
});
// 开启线程处理部分
ExecutorService pool = Executors.newSingleThreadExecutor();
...
if (isSwitchOn(R.id.fall_detect)) {
pool.execute(new CheckFallAndMoveThread(buf, width, height));
}
这样的话,只允许一个线程执行,多来了的,就排队等待处理,这样便实现了一帧一帧处理,并且还不会阻塞主线程。但是很可惜,这样会造成OOM。
原因
so库处理的时间达到了2s左右(处理的图片没有经过resize),有点长。这样的话,每个需要处理的Runnable都需要一定的空间去存储这个图片,并且此种Executor是Runnable是无限长的,长度会自动变化,空间很快就会用完,也是合情合理。
解决办法
看了一下,默认提供的几种线程池,并不能达到自己的需求,只能自己重新设置一下其中的参数,然后利用这些参数,设置成自己想要的那种模式,即队列长度有限,按顺序执行,然后宁愿少处理几帧,也要避免OOM。
public class CalTaskThreadExecutor {
private static final ExecutorService instance = new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<Runnable>(2),
new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable r) {
return new Thread(r, "SingleTaskPoolThread #" + mCount.getAndIncrement());
}
},
new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
Log.e("TAG", "超了");
executor.remove(r);
}
});
public static ExecutorService getInstance(){
return instance;
}
}
十分感谢这篇博客,让我大致明白了其中参数所代表的意义,并按照自己的需求整个相应线程池出来。线程池,这一篇或许就够了。