Я делаю приложение для Android, которое использует GLSurfaceView и мультимедийные эффекты Android для применения фильтров к изображениям. Реализация работает нормально, за исключением того, что в приложении возникает утечка памяти. При каждом добавлении эффекта в графическую память использование приложения значительно увеличивается, и эта память никогда не освобождается.
Кто-нибудь знает, как уменьшить объем памяти в этом классе, или, по крайней мере, знает, что вызывает интенсивное использование памяти, и указывает мне верное направление для решения этой проблемы?
Я пытался дозвониться до GLES20.glDeleteTextures(2, mTextures, 0)
как раз перед GLES20.glGenTextures(2, mTextures, 0)
, но это не помогло. Я также экспериментировал с GLES20.glFinish()
и GLES20.glFlush()
и mEffectContext.release()
безуспешно или без каких-либо заметных изменений.
Я приложил скриншот из выполненного профилирования, а также соответствующие фрагменты самого класса ниже.
Это мой первый вопрос о переполнении стека, поэтому не стесняйтесь поправлять меня, если я нарушил все правила сообщества.
class ImageFilterView extends GLSurfaceView implements GLSurfaceView.Renderer {
private int[] mTextures = new int[2];
private void init() {
setEGLContextClientVersion(2);
setRenderer(this);
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
setFilterEffect(NONE);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
if (mTexRenderer != null) {
mTexRenderer.updateViewSize(width, height);
}
}
@Override
public void onDrawFrame(GL10 gl) {
if (!mInitialized) {
//Only need to do this once
mEffectContext = EffectContext.createWithCurrentGlContext();
mTexRenderer.init();
loadTextures();
mInitialized = true;
}
if (mCurrentEffect != NONE || mCustomEffect != null) {
//if an effect is chosen initialize it and apply it to the texture
initEffect();
applyEffect();
}
renderResult();
if (isSaveImage) {
final Bitmap mFilterBitmap = BitmapUtil.createBitmapFromGLSurface(this, gl);
Log.e(TAG, "onDrawFrame: " + mFilterBitmap);
isSaveImage = false;
if (mOnSaveBitmap != null) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
mOnSaveBitmap.onBitmapReady(mFilterBitmap);
}
});
}
}
}
void setFilterEffect(PhotoFilter effect) {
mCurrentEffect = effect;
mCustomEffect = null;
requestRender();
}
void saveBitmap(OnSaveBitmap onSaveBitmap) {
mOnSaveBitmap = onSaveBitmap;
isSaveImage = true;
requestRender();
}
private void loadTextures() {
GLES20.glGenTextures(2, mTextures, 0);
// Load input bitmap
if (mSourceBitmap != null) {
mImageWidth = mSourceBitmap.getWidth();
mImageHeight = mSourceBitmap.getHeight();
mTexRenderer.updateTextureSize(mImageWidth, mImageHeight);
// Upload to texture
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextures[0]);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, mSourceBitmap, 0);
// Set texture parameters
GLToolbox.initTexParams();
}
}
private void initEffect() {
EffectFactory effectFactory = mEffectContext.getFactory();
if (mEffect != null) {
mEffect.release();
}
if (mCustomEffect != null) {
mEffect = effectFactory.createEffect(mCustomEffect.getEffectName());
Map<String, Object> parameters = mCustomEffect.getParameters();
for (Map.Entry<String, Object> param : parameters.entrySet()) {
mEffect.setParameter(param.getKey(), param.getValue());
}
} else {
// Initialize the correct effect based on the selected menu/action item
switch (mCurrentEffect) {
case VIGNETTE:
mEffect = effectFactory.createEffect(EFFECT_VIGNETTE);
mEffect.setParameter("scale", .5f);
break;
}
}
}
private void applyEffect() {
mEffect.apply(mTextures[0], mImageWidth, mImageHeight, mTextures[1]);
}
private void renderResult() {
if (mCurrentEffect != NONE || mCustomEffect != null) {
// if no effect is chosen, just render the original bitmap
mTexRenderer.renderTexture(mTextures[1]);
} else {
// render the result of applyEffect()
mTexRenderer.renderTexture(mTextures[0]);
}
}
}
Снимок экрана профилирования: память увеличивается при каждом добавлении фильтра