Android资源GC问题

时间:2018-11-19 17:37:53

标签: android bitmap opengl-es resources ram

我正在使用

Drawable drawable = res.getDrawable(id);
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444);
Canvas canvas = new Canvas(bitmap);
bitmap.eraseColor(0);
drawable.setBounds(0,0, width, height);
drawable.draw(canvas);
return load(bitmap, linear);

以给定的宽度和高度将资源ID中的drawable加载到OpenGL中。 (使用

android.opengl.GLUtils.texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);

) 加载函数执行GL调用,并且还调用bitmap.recycle()。

我自己指定宽度和高度,因为Android会将分辨率与屏幕尺寸匹配,这是我不希望的。

现在我的问题(这部分工作正常): 如果我是第一次从Android Studio启动我的应用程序,则一切正常;但是,如果我想重新启动它,它会因OutOfMemoryError而崩溃。在两种情况下,我都进行完全相同的通话。

我将问题定位在Android的资源管理中,如您在堆分析中所看到的: my most expensive allocations

我的图像的原始大小均小于9 MB(512x512,RGBA,所以1 MB)。 我如何防止Android存储这些大字节数组,这些数组可能意味着某种缓存;但是,在安装应用程序后第一次启动时却无法运行?

我正在Android 6.0.1,API版本23,Galaxy S5上进行测试。

2 个答案:

答案 0 :(得分:0)

texImage2D的实现如下所示:

public static void texImage2D(int target, int level, int internalformat,
        Bitmap bitmap, int border) {
    if (bitmap == null) {
        throw new NullPointerException("texImage2D can't be used with a null Bitmap");
    }
    if (bitmap.isRecycled()) {
        throw new IllegalArgumentException("bitmap is recycled");
    }
    if (native_texImage2D(target, level, internalformat, bitmap, -1, border)!=0) {
        throw new IllegalArgumentException("invalid Bitmap format");
    }
}

看起来好像没有回收任何东西。您确定没有将巨大的位图加载到内存中吗?即使不仅仅一次,两次调用就足以保证您的应用程序发生巨大的爆炸(我见过它在我的应用程序中发生过很多次)。请记住,重新启动活动并不意味着重新启动过程。

在首次加载之前运行Android Profiler,并检查它占用了多少内存。

此外,您可以自己缓存和重用位图。

答案 1 :(得分:0)

我通过将文件放入资源目录的原始文件夹并使用加载它们来解决了(我自己)

fun loadBitmap(res: Resources, rawId: Int): Bitmap {
    val inputStream = BufferedInputStream(res.openRawResource(rawId))
    return BitmapFactory.decodeStream(inputStream)
}

然后致电

load(bitmap, linear);

bitmap.recycle()

像以前一样。 幸运的是,这些都是png / jpeg文件,因此我不需要drawables文件夹的其他功能。使用此功能,他们将自动使用正确的分辨率。

我的Java RAM分配现在从原来的110 MB恢复到了25 MB至35 MB: