Я полностью понимаю, что "преждевременная оптимизация - корень всего зла. " Однако я дошел до того, что считаю, что оптимизация, которую я хочу сделать, больше не может считаться "преждевременной" .
Я пишу приложение для Android, которое, помимо прочего, передает поток живого изображения с USB-устройства, выполняет некоторую обработку изображения с помощью OpenCV, преобразует кадр в растровое изображение, а затем отображает это растровое изображение в SurfaceView в реальном времени. время.
У меня все работает, (прямая трансляция корректно отображается в SurfaceView), и инструмент «Профилировщик» в Android Studio показывает, что я хорошо справился с управлением памятью (обратите внимание, что сборщик мусора не запускается один раз в 10 секунд, показанные ниже ):
Однако, поскольку изображение, которое я передаю, имеет низкое разрешение (320x180), когда я рендерим его непосредственно в SurfaceView, оно фактически оказывается довольно маленьким на экране устройства.
Таким образом, я решил масштабировать растровое изображение до максимального размера, который поместился бы в SurfaceView, перед его отображением на экране. Однако после этого я с ужасом обнаружил, что график использования памяти теперь выглядит ужасно! (Сборщик мусора работает чаще, чем раз в секунду! )
Вот соответствующие фрагменты кода:
Перед масштабированием растрового изображения (график чистой памяти):
canvas = getHolder().lockCanvas();
openCvMat = frameQueue.take();
Utils.matToBitmap(openCvMat, bitmapFromMat);
mat.release();
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(bitmapFromMat, 0, 0, null);
getHolder().unlockCanvasAndPost(canvas);
После масштабирования растрового изображения (граф ужасной памяти):
canvas = getHolder().lockCanvas();
openCvMat = frameQueue.take();
Utils.matToBitmap(openCvMat, bitmapFromMat);
mat.release();
canvas.drawColor(Color.BLACK);
Bitmap scaled = scaleBitmapToViewport(bitmapFromMat);
canvas.drawBitmap(scaled, 0, 0, null);
scaled.recycle();
getHolder().unlockCanvasAndPost(canvas);
scaleBitmapToViewport()
метод:
private Bitmap scaleBitmapToViewport(Bitmap bitmap)
{
//Landscape
if((canvas.getHeight() * aspectRatio) < canvas.getWidth())
{
return Bitmap.createScaledBitmap(bitmap, (int) Math.round(canvas.getHeight() * aspectRatio), canvas.getHeight(), true);
}
else //Portrait
{
return Bitmap.createScaledBitmap(bitmap, canvas.getWidth(), (int) Math.round(canvas.getWidth() / aspectRatio), true);
}
}
Так что, похоже, Bitmap.createScaledBitmap()
является виновником. Кто-нибудь знает другой способ сделать то же самое, что не дает сборщику мусора за свои деньги?