Android 位图内存问题 - 错误 : Out of memory on a 8294416-byte allocation

标签 android bitmap imageview out-of-memory heap-memory

我目前正在开发一个讲述故事的应用程序。这个故事包含“场景”,其中包含多个通过 ImageView 显示的 JPEG 和 PNG 文件。我创建了 ImageView 并通过以下函数将其添加到布局中:

private ImageView newImage(Show show)
{
    ImageView iv = new ImageView(this);
    String filePath = comin.generateFilePath(show);
    Log.i(TAG, "newImage, filePath = " + filePath + " id = " + show.id);
    WeakReference<Bitmap> bmp = new WeakReference<Bitmap>(scaleBitmap(filePath)); //added 4/1/13
    //Bitmap bmp = scaleBitmap(filePath);
    Log.i(TAG, "newImage, width = " + bmp.get().getWidth() + ", height = " + bmp.get().getHeight());
    iv.setImageBitmap(bmp.get());
    iv.setScaleType(ImageView.ScaleType.FIT_XY);
    iv.setId(show.id);

    //set visibility
    if (show.visible)
        iv.setVisibility(View.VISIBLE);
    else
        iv.setVisibility(View.INVISIBLE);

    //set dimensions
    int width = (app.getWidth() * show.dimX) / 100;
    int height = (app.getHeight() * show.dimY) / 100;
    RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(width, height);
    iv.setLayoutParams(rlp);

    return iv;
}  

场景结束后,我会清除所有 ImageView,除了一个没有图像且仅用于监听触摸事件的 ImageView。

private void clearScene(boolean clearTouch)
{
    RelativeLayout parent = (RelativeLayout) findViewById(R.id.relative_layout);
    logMemory("clearScene, START");

    int count = parent.getChildCount();
    for (int a = count - 1; a >= 0; a--)
    {
        int id = parent.getChildAt(a).getId();
        String message = "clearScene id = " + id + ", count = " + count + ", a = " + a;
        if (id == TOUCH_VIEW_ID && !clearTouch)
        {
            message = message + ", ignore touch screen view";
        }
        else
        {
            unbindView(parent.getChildAt(a));
            parent.getChildAt(a).clearAnimation();
            parent.removeView(parent.getChildAt(a));
            message = message + ", unbindView, clearAnimation, removeView";
        }
        Log.i(TAG, message);
        logMemory("clearScene, CLEARED VIEW");
    }

    handler.removeCallbacksAndMessages(null);  //stop any future scheduled tasks from triggering
    logMemory("clearScene, BEFORE TRASH COLLECTOR");
    System.gc();
    logMemory("clearScene, AFTER TRASH COLLECTOR");
}

如您所见,我调用了 unbindView() 方法,以尝试清除任何类型的可能内存泄漏。

private void unbindView(View view)
{
    String message = "unbindView, id = " + view.getId();
    try {view.setOnClickListener(null);} catch (Throwable mayHappen) {};
    try {view.setOnCreateContextMenuListener(null);} catch (Throwable mayHappen) {};
    try {view.setOnFocusChangeListener(null);} catch (Throwable mayHappen) {};
    try {view.setOnKeyListener(null);} catch (Throwable mayHappen) {};
    try {view.setOnLongClickListener(null);} catch (Throwable mayHappen) {};
    try {view.setOnClickListener(null);} catch (Throwable mayHappen) {};

    if (view.getBackground() != null)
    {
        message = message + ", setBackgroundCallback(null)";
        view.getBackground().setCallback(null);
    }

    if (view instanceof ImageView)
    {
        if (((ImageView)view).getDrawable() != null)
        {
            if (((ImageView)view).getDrawable() instanceof BitmapDrawable)
            {
                message = message + ", recycle bitmap";
                ((BitmapDrawable)((ImageView)view).getDrawable()).getBitmap().recycle();
            }
            message = message + ", setDrawableCallback(null)";
            ((ImageView)view).getDrawable().setCallback(null);
        }
        message = message + ", setImageBitmap(null), setBackgroundDrawable(null)";
        ((ImageView) view).setImageBitmap(null);
        ((ImageView) view).setBackgroundDrawable(null);
    }
    Log.i(TAG, message);
}

一旦所有 ImageView 都没有边界,我就在 clearScene 函数中运行垃圾收集器。

***编辑(2013 年 4 月 2 日)好的,经过一些研究和反复试验,我改变了我的内存记录。以下是相关方法:

在 onResume() 中,我根据 Android 版本将一个 bool 值设置为 true(以确定它是使用 native 内存还是 Java 内存用于位图),然后我将旧内存值的默认值初始化为 0;

@Override
protected void onResume() 
{
    super.onResume();

    if (android.os.Build.VERSION.SDK_INT >= 11) debugJavaMemory = true;
    else debugNativeMemory = true;
    availableJavaMemoryOld = 0;
    availableNativeMemoryOld = 0;
    dialogDebug();
}  

这是我的日志功能。它根据当前版本的 Android 是使用 native 内存还是 Java 内存来存储位图进行记录。

private void logMemory(String callingFunction)
{
    if (debugJavaMemory)
    {
        long max = Runtime.getRuntime().maxMemory() / 1024;
        long used = Runtime.getRuntime().totalMemory() / 1024;
        long available = max - used;
        long change = available - availableJavaMemoryOld;
        if (availableJavaMemoryOld != 0)
            Log.i(TAG_MEMORY, "jMEM M:" + max + ", U:" + used + ", A:" + available + ", C:" + change + ", " + callingFunction);
        availableJavaMemoryOld = available;
    }
    else if (debugNativeMemory)
    {
        long max = Debug.getNativeHeapSize() / 1024;
        long used = Debug.getNativeHeapAllocatedSize() / 1024;
        long available = max - used;
        long change = available - availableNativeMemoryOld;
        if (availableNativeMemoryOld != 0)
            Log.i(TAG_MEMORY, "nMEM M:" + max + ", U:" + used + ", A:" + available + ", C:" + change + ", " + callingFunction);
        availableNativeMemoryOld = available;
    }
}  

如果您查看我从运行 Android 10 (2.3.3) 的模拟器收集的日志,垃圾收集器似乎运行良好!我唯一注意到的奇怪之处是最大 native 内存可以动态增加!?

图例:M:(最大内存),U:(已用内存),A:(可用内存),C:(可用内存变化),调用日志函数的函数

04-03 02:34:20.758: I/MEMORY(1045): nMEM M:18336, U:13287, A:5049, C:-2549, loadScene, ADDED IMAGE b:0, s:0, id:0
04-03 02:34:21.267: I/MEMORY(1045): nMEM M:21568, U:21391, A:177, C:-4872, loadScene, ADDED IMAGE b:0, s:0, id:1
04-03 02:34:35.227: I/MEMORY(1045): nMEM M:21568, U:13288, A:8280, C:8103, clearScene, CLEARED VIEW id:1
04-03 02:34:35.267: I/MEMORY(1045): nMEM M:21568, U:5184, A:16384, C:8104, clearScene, CLEARED VIEW id:0
04-03 02:34:35.327: I/MEMORY(1045): nMEM M:21568, U:4977, A:16591, C:207, clearScene, AFTER TRASH COLLECTOR
04-03 02:34:36.067: I/MEMORY(1045): nMEM M:21568, U:13082, A:8486, C:-8105, loadScene, ADDED IMAGE b:1, s:0, id:0
04-03 02:34:47.177: I/MEMORY(1045): nMEM M:21568, U:4979, A:16589, C:8103, clearScene, CLEARED VIEW id:0
04-03 02:34:47.277: I/MEMORY(1045): nMEM M:21568, U:4978, A:16590, C:1, clearScene, AFTER TRASH COLLECTOR
04-03 02:34:47.997: I/MEMORY(1045): nMEM M:21568, U:13082, A:8486, C:-8104, loadScene, ADDED IMAGE b:1, s:1, id:0
04-03 02:34:49.307: I/MEMORY(1045): nMEM M:26224, U:21186, A:5038, C:-3448, loadScene, ADDED IMAGE b:1, s:1, id:1
04-03 02:34:50.597: I/MEMORY(1045): nMEM M:34328, U:29290, A:5038, C:0, loadScene, ADDED IMAGE b:1, s:1, id:2
04-03 02:34:51.839: I/MEMORY(1045): nMEM M:42432, U:37395, A:5037, C:-1, loadScene, ADDED IMAGE b:1, s:1, id:3
04-03 02:35:00.377: I/MEMORY(1045): nMEM M:42432, U:29293, A:13139, C:8102, clearScene, CLEARED VIEW id:3
04-03 02:35:00.387: I/MEMORY(1045): nMEM M:42432, U:21189, A:21243, C:8104, clearScene, CLEARED VIEW id:2
04-03 02:35:00.397: I/MEMORY(1045): nMEM M:42432, U:13085, A:29347, C:8104, clearScene, CLEARED VIEW id:1
04-03 02:35:00.407: I/MEMORY(1045): nMEM M:42432, U:4982, A:37450, C:8103, clearScene, CLEARED VIEW id:0
04-03 02:35:00.449: I/MEMORY(1045): nMEM M:42432, U:4978, A:37454, C:4, clearScene, AFTER TRASH COLLECTOR
04-03 02:35:01.217: I/MEMORY(1045): nMEM M:42432, U:13083, A:29349, C:-8105, loadScene, ADDED IMAGE b:1, s:2, id:0
04-03 02:35:23.458: I/MEMORY(1045): nMEM M:42432, U:4979, A:37453, C:8104, clearScene, CLEARED VIEW id:0
04-03 02:35:23.508: I/MEMORY(1045): nMEM M:42432, U:4978, A:37454, C:1, clearScene, AFTER TRASH COLLECTOR
04-03 02:35:24.777: I/MEMORY(1045): nMEM M:42432, U:13082, A:29350, C:-8104, loadScene, ADDED IMAGE b:1, s:3, id:0
04-03 02:35:25.719: I/MEMORY(1045): nMEM M:42432, U:21186, A:21246, C:-8104, loadScene, ADDED IMAGE b:1, s:3, id:1
04-03 02:35:26.457: I/MEMORY(1045): nMEM M:42432, U:29291, A:13141, C:-8105, loadScene, ADDED IMAGE b:1, s:3, id:2
04-03 02:35:55.008: I/MEMORY(1045): nMEM M:42432, U:21187, A:21245, C:8104, clearScene, CLEARED VIEW id:2
04-03 02:35:55.027: I/MEMORY(1045): nMEM M:42432, U:13083, A:29349, C:8104, clearScene, CLEARED VIEW id:1
04-03 02:35:55.037: I/MEMORY(1045): nMEM M:42432, U:4979, A:37453, C:8104, clearScene, CLEARED VIEW id:0
04-03 02:35:55.077: I/MEMORY(1045): nMEM M:42432, U:4978, A:37454, C:1, clearScene, AFTER TRASH COLLECTOR
04-03 02:35:55.829: I/MEMORY(1045): nMEM M:42432, U:13083, A:29349, C:-8105, loadScene, ADDED IMAGE b:1, s:4, id:0
04-03 02:35:56.427: I/MEMORY(1045): nMEM M:42432, U:21187, A:21245, C:-8104, loadScene, ADDED IMAGE b:1, s:4, id:1
04-03 02:36:00.257: I/MEMORY(1045): nMEM M:42432, U:13083, A:29349, C:8104, clearScene, CLEARED VIEW id:1
04-03 02:36:00.278: I/MEMORY(1045): nMEM M:42432, U:4979, A:37453, C:8104, clearScene, CLEARED VIEW id:0
04-03 02:36:00.318: I/MEMORY(1045): nMEM M:42432, U:4978, A:37454, C:1, clearScene, AFTER TRASH COLLECTOR
04-03 02:36:01.687: I/MEMORY(1045): nMEM M:42432, U:13083, A:29349, C:-8105, loadScene, ADDED IMAGE b:1, s:5, id:0
04-03 02:36:06.437: I/MEMORY(1045): nMEM M:42432, U:4979, A:37453, C:8104, clearScene, CLEARED VIEW id:0
04-03 02:36:06.487: I/MEMORY(1045): nMEM M:42432, U:4978, A:37454, C:1, clearScene, AFTER TRASH COLLECTOR
04-03 02:36:07.777: I/MEMORY(1045): nMEM M:42432, U:13082, A:29350, C:-8104, loadScene, ADDED IMAGE b:1, s:6, id:0
04-03 02:36:09.297: I/MEMORY(1045): nMEM M:42432, U:4978, A:37454, C:8104, clearScene, CLEARED VIEW id:0
04-03 02:36:09.337: I/MEMORY(1045): nMEM M:42432, U:4978, A:37454, C:0, clearScene, AFTER TRASH COLLECTOR
04-03 02:36:10.727: I/MEMORY(1045): nMEM M:42432, U:13082, A:29350, C:-8104, loadScene, ADDED IMAGE b:1, s:7, id:0
04-03 02:36:20.947: I/MEMORY(1045): nMEM M:42432, U:4978, A:37454, C:8104, clearScene, CLEARED VIEW id:0
04-03 02:36:20.987: I/MEMORY(1045): nMEM M:42432, U:4978, A:37454, C:0, clearScene, AFTER TRASH COLLECTOR
04-03 02:36:22.367: I/MEMORY(1045): nMEM M:42432, U:13082, A:29350, C:-8104, loadScene, ADDED IMAGE b:1, s:8, id:0
04-03 02:36:23.317: I/MEMORY(1045): nMEM M:42432, U:21187, A:21245, C:-8105, loadScene, ADDED IMAGE b:1, s:8, id:1
04-03 02:36:23.887: I/MEMORY(1045): nMEM M:42432, U:29291, A:13141, C:-8104, loadScene, ADDED IMAGE b:1, s:8, id:2
04-03 02:36:26.507: I/MEMORY(1045): nMEM M:42432, U:21187, A:21245, C:8104, clearScene, CLEARED VIEW id:2
04-03 02:36:26.517: I/MEMORY(1045): nMEM M:42432, U:13083, A:29349, C:8104, clearScene, CLEARED VIEW id:1
04-03 02:36:26.527: I/MEMORY(1045): nMEM M:42432, U:4979, A:37453, C:8104, clearScene, CLEARED VIEW id:0
04-03 02:36:26.577: I/MEMORY(1045): nMEM M:42432, U:4978, A:37454, C:1, clearScene, AFTER TRASH COLLECTOR
04-03 02:36:27.797: I/MEMORY(1045): nMEM M:42432, U:13083, A:29349, C:-8105, loadScene, ADDED IMAGE b:1, s:9, id:0
04-03 02:36:29.248: I/MEMORY(1045): nMEM M:42432, U:4979, A:37453, C:8104, clearScene, CLEARED VIEW id:0
04-03 02:36:29.287: I/MEMORY(1045): nMEM M:42432, U:4978, A:37454, C:1, clearScene, AFTER TRASH COLLECTOR
04-03 02:36:30.547: I/MEMORY(1045): nMEM M:42432, U:13082, A:29350, C:-8104, loadScene, ADDED IMAGE b:1, s:10, id:0
04-03 02:36:32.177: I/MEMORY(1045): nMEM M:42432, U:4978, A:37454, C:8104, clearScene, CLEARED VIEW id:0
04-03 02:36:32.228: I/MEMORY(1045): nMEM M:42432, U:4978, A:37454, C:0, clearScene, AFTER TRASH COLLECTOR
04-03 02:36:33.467: I/MEMORY(1045): nMEM M:42432, U:13082, A:29350, C:-8104, loadScene, ADDED IMAGE b:1, s:11, id:0
04-03 02:36:33.977: I/MEMORY(1045): nMEM M:42432, U:21187, A:21245, C:-8105, loadScene, ADDED IMAGE b:1, s:11, id:1
04-03 02:36:34.527: I/MEMORY(1045): nMEM M:42432, U:29291, A:13141, C:-8104, loadScene, ADDED IMAGE b:1, s:11, id:2
04-03 02:36:35.058: I/MEMORY(1045): nMEM M:42432, U:37395, A:5037, C:-8104, loadScene, ADDED IMAGE b:1, s:11, id:3
04-03 02:36:41.260: I/MEMORY(1045): nMEM M:42432, U:29291, A:13141, C:8104, clearScene, CLEARED VIEW id:3
04-03 02:36:41.267: I/MEMORY(1045): nMEM M:42432, U:21187, A:21245, C:8104, clearScene, CLEARED VIEW id:2
04-03 02:36:41.278: I/MEMORY(1045): nMEM M:42432, U:13083, A:29349, C:8104, clearScene, CLEARED VIEW id:1
04-03 02:36:41.287: I/MEMORY(1045): nMEM M:42432, U:4979, A:37453, C:8104, clearScene, CLEARED VIEW id:0
04-03 02:36:41.337: I/MEMORY(1045): nMEM M:42432, U:4979, A:37453, C:0, clearScene, AFTER TRASH COLLECTOR
04-03 02:36:42.618: I/MEMORY(1045): nMEM M:42432, U:13083, A:29349, C:-8104, loadScene, ADDED IMAGE b:2, s:0, id:0
04-03 02:37:00.550: I/MEMORY(1045): nMEM M:42432, U:4979, A:37453, C:8104, clearScene, CLEARED VIEW id:0
04-03 02:37:00.587: I/MEMORY(1045): nMEM M:42432, U:4979, A:37453, C:0, clearScene, AFTER TRASH COLLECTOR
04-03 02:37:01.817: I/MEMORY(1045): nMEM M:42432, U:13083, A:29349, C:-8104, loadScene, ADDED IMAGE b:2, s:1, id:0
04-03 02:37:03.347: I/MEMORY(1045): nMEM M:42432, U:4979, A:37453, C:8104, clearScene, CLEARED VIEW id:0
04-03 02:37:03.397: I/MEMORY(1045): nMEM M:42432, U:4979, A:37453, C:0, clearScene, AFTER TRASH COLLECTOR
04-03 02:37:04.607: I/MEMORY(1045): nMEM M:42432, U:13083, A:29349, C:-8104, loadScene, ADDED IMAGE b:2, s:2, id:0
04-03 02:37:05.258: I/MEMORY(1045): nMEM M:42432, U:21187, A:21245, C:-8104, loadScene, ADDED IMAGE b:2, s:2, id:1
04-03 02:37:07.677: I/MEMORY(1045): nMEM M:42432, U:13083, A:29349, C:8104, clearScene, CLEARED VIEW id:1
04-03 02:37:07.687: I/MEMORY(1045): nMEM M:42432, U:4979, A:37453, C:8104, clearScene, CLEARED VIEW id:0
04-03 02:37:07.737: I/MEMORY(1045): nMEM M:42432, U:4979, A:37453, C:0, clearScene, AFTER TRASH COLLECTOR
04-03 02:37:09.017: I/MEMORY(1045): nMEM M:42432, U:13083, A:29349, C:-8104, loadScene, ADDED IMAGE b:2, s:3, id:0
04-03 02:37:10.327: I/MEMORY(1045): nMEM M:42432, U:21187, A:21245, C:-8104, loadScene, ADDED IMAGE b:2, s:3, id:1
04-03 02:37:13.330: I/MEMORY(1045): nMEM M:42432, U:13083, A:29349, C:8104, clearScene, CLEARED VIEW id:1
04-03 02:37:13.337: I/MEMORY(1045): nMEM M:42432, U:4979, A:37453, C:8104, clearScene, CLEARED VIEW id:0
04-03 02:37:13.387: I/MEMORY(1045): nMEM M:42432, U:4979, A:37453, C:0, clearScene, AFTER TRASH COLLECTOR
04-03 02:37:14.697: I/MEMORY(1045): nMEM M:42432, U:13083, A:29349, C:-8104, loadScene, ADDED IMAGE b:2, s:4, id:0
04-03 02:37:16.037: I/MEMORY(1045): nMEM M:42432, U:21187, A:21245, C:-8104, loadScene, ADDED IMAGE b:2, s:4, id:1
04-03 02:37:17.367: I/MEMORY(1045): nMEM M:42432, U:29292, A:13140, C:-8105, loadScene, ADDED IMAGE b:2, s:4, id:2
04-03 02:37:19.087: I/MEMORY(1045): nMEM M:42432, U:37396, A:5036, C:-8104, loadScene, ADDED IMAGE b:2, s:4, id:3
04-03 02:37:44.347: I/MEMORY(1045): nMEM M:42432, U:29293, A:13139, C:8103, clearScene, CLEARED VIEW id:3
04-03 02:37:44.357: I/MEMORY(1045): nMEM M:42432, U:21189, A:21243, C:8104, clearScene, CLEARED VIEW id:2
04-03 02:37:44.367: I/MEMORY(1045): nMEM M:42432, U:13085, A:29347, C:8104, clearScene, CLEARED VIEW id:1
04-03 02:37:44.377: I/MEMORY(1045): nMEM M:42432, U:4981, A:37451, C:8104, clearScene, CLEARED VIEW id:0
04-03 02:37:44.437: I/MEMORY(1045): nMEM M:42432, U:4979, A:37453, C:2, clearScene, AFTER TRASH COLLECTOR
04-03 02:37:45.667: I/MEMORY(1045): nMEM M:42432, U:13083, A:29349, C:-8104, loadScene, ADDED IMAGE b:2, s:5, id:0
04-03 02:37:46.917: I/MEMORY(1045): nMEM M:42432, U:21188, A:21244, C:-8105, loadScene, ADDED IMAGE b:2, s:5, id:1
04-03 02:37:48.167: I/MEMORY(1045): nMEM M:42432, U:29292, A:13140, C:-8104, loadScene, ADDED IMAGE b:2, s:5, id:2
04-03 02:37:49.807: I/MEMORY(1045): nMEM M:42432, U:37396, A:5036, C:-8104, loadScene, ADDED IMAGE b:2, s:5, id:3
04-03 02:38:08.239: I/MEMORY(1045): nMEM M:42432, U:29293, A:13139, C:8103, clearScene, CLEARED VIEW id:3
04-03 02:38:08.258: I/MEMORY(1045): nMEM M:42432, U:21189, A:21243, C:8104, clearScene, CLEARED VIEW id:2
04-03 02:38:08.267: I/MEMORY(1045): nMEM M:42432, U:13086, A:29346, C:8103, clearScene, CLEARED VIEW id:1
04-03 02:38:08.277: I/MEMORY(1045): nMEM M:42432, U:4982, A:37450, C:8104, clearScene, CLEARED VIEW id:0
04-03 02:38:08.317: I/MEMORY(1045): nMEM M:42432, U:4979, A:37453, C:3, clearScene, AFTER TRASH COLLECTOR
04-03 02:38:09.527: I/MEMORY(1045): nMEM M:42432, U:13083, A:29349, C:-8104, loadScene, ADDED IMAGE b:2, s:6, id:0  

如前所述,在 ImageView 解除绑定(bind)后清理内存!

这是我从运行 Android 17 (4.2) 的损坏的 Nexus 7 中收集的日志。真的很难理解这里是如何使用内存的。从来都不一致!有时在我加载 ImageView 时未分配内存。有时只有在加载新的 ImageView 时才会清除内存。

图例:M:(最大内存),U:(已用内存),A:(可用内存),C:(可用内存变化),调用日志函数的函数

04-02 22:37:05.866: I/MEMORY(15827): jMEM M:65536, U:21300, A:44236, C:0, loadScene, ADDED IMAGE b:0, s:0, id:0
04-02 22:37:06.136: I/MEMORY(15827): jMEM M:65536, U:29444, A:36092, C:-8144, loadScene, ADDED IMAGE b:0, s:0, id:1
04-02 22:37:19.806: I/MEMORY(15827): jMEM M:65536, U:29432, A:36104, C:12, clearScene, CLEARED VIEW id:1
04-02 22:37:19.806: I/MEMORY(15827): jMEM M:65536, U:29432, A:36104, C:0, clearScene, CLEARED VIEW id:0
04-02 22:37:19.836: I/MEMORY(15827): jMEM M:65536, U:29432, A:36104, C:0, clearScene, AFTER TRASH COLLECTOR
04-02 22:37:20.116: I/MEMORY(15827): jMEM M:65536, U:37536, A:28000, C:-8104, loadScene, ADDED IMAGE b:1, s:0, id:0
04-02 22:37:28.456: I/MEMORY(15827): jMEM M:65536, U:37532, A:28004, C:4, clearScene, CLEARED VIEW id:0
04-02 22:37:28.486: I/MEMORY(15827): jMEM M:65536, U:37532, A:28004, C:0, clearScene, AFTER TRASH COLLECTOR
04-02 22:37:28.756: I/MEMORY(15827): jMEM M:65536, U:37532, A:28004, C:0, loadScene, ADDED IMAGE b:1, s:1, id:0
04-02 22:37:29.226: I/MEMORY(15827): jMEM M:65536, U:37532, A:28004, C:0, loadScene, ADDED IMAGE b:1, s:1, id:1
04-02 22:37:29.706: I/MEMORY(15827): jMEM M:65536, U:45636, A:19900, C:-8104, loadScene, ADDED IMAGE b:1, s:1, id:2
04-02 22:37:30.156: I/MEMORY(15827): jMEM M:65536, U:53740, A:11796, C:-8104, loadScene, ADDED IMAGE b:1, s:1, id:3
04-02 22:37:38.676: I/MEMORY(15827): jMEM M:65536, U:53732, A:11804, C:8, clearScene, CLEARED VIEW id:3
04-02 22:37:38.676: I/MEMORY(15827): jMEM M:65536, U:53732, A:11804, C:0, clearScene, CLEARED VIEW id:2
04-02 22:37:38.676: I/MEMORY(15827): jMEM M:65536, U:53732, A:11804, C:0, clearScene, CLEARED VIEW id:1
04-02 22:37:38.676: I/MEMORY(15827): jMEM M:65536, U:53732, A:11804, C:0, clearScene, CLEARED VIEW id:0
04-02 22:37:38.696: I/MEMORY(15827): jMEM M:65536, U:53732, A:11804, C:0, clearScene, AFTER TRASH COLLECTOR
04-02 22:37:38.966: I/MEMORY(15827): jMEM M:65536, U:53732, A:11804, C:0, loadScene, ADDED IMAGE b:1, s:2, id:0
04-02 22:37:48.156: I/MEMORY(15827): jMEM M:65536, U:53732, A:11804, C:0, clearScene, CLEARED VIEW id:0
04-02 22:37:48.216: I/MEMORY(15827): jMEM M:65536, U:37532, A:28004, C:16200, clearScene, AFTER TRASH COLLECTOR
04-02 22:37:48.676: I/MEMORY(15827): jMEM M:65536, U:37532, A:28004, C:0, loadScene, ADDED IMAGE b:1, s:3, id:0
04-02 22:37:49.256: I/MEMORY(15827): jMEM M:65536, U:37532, A:28004, C:0, loadScene, ADDED IMAGE b:1, s:3, id:1
04-02 22:37:49.716: I/MEMORY(15827): jMEM M:65536, U:45636, A:19900, C:-8104, loadScene, ADDED IMAGE b:1, s:3, id:2
04-02 22:38:07.426: I/MEMORY(15827): jMEM M:65536, U:45632, A:19904, C:4, clearScene, CLEARED VIEW id:2
04-02 22:38:07.426: I/MEMORY(15827): jMEM M:65536, U:45632, A:19904, C:0, clearScene, CLEARED VIEW id:1
04-02 22:38:07.426: I/MEMORY(15827): jMEM M:65536, U:45632, A:19904, C:0, clearScene, CLEARED VIEW id:0
04-02 22:38:07.496: I/MEMORY(15827): jMEM M:65536, U:45632, A:19904, C:0, clearScene, AFTER TRASH COLLECTOR
04-02 22:38:07.766: I/MEMORY(15827): jMEM M:65536, U:45632, A:19904, C:0, loadScene, ADDED IMAGE b:1, s:4, id:0
04-02 22:38:08.096: I/MEMORY(15827): jMEM M:65536, U:53736, A:11800, C:-8104, loadScene, ADDED IMAGE b:1, s:4, id:1
04-02 22:38:10.896: I/MEMORY(15827): jMEM M:65536, U:53736, A:11800, C:0, clearScene, CLEARED VIEW id:1
04-02 22:38:10.896: I/MEMORY(15827): jMEM M:65536, U:53736, A:11800, C:0, clearScene, CLEARED VIEW id:0
04-02 22:38:10.916: I/MEMORY(15827): jMEM M:65536, U:53736, A:11800, C:0, clearScene, AFTER TRASH COLLECTOR
04-02 22:38:11.436: I/MEMORY(15827): jMEM M:65536, U:53736, A:11800, C:0, loadScene, ADDED IMAGE b:1, s:5, id:0
04-02 22:38:19.356: I/MEMORY(15827): jMEM M:65536, U:53732, A:11804, C:4, clearScene, CLEARED VIEW id:0
04-02 22:38:19.386: I/MEMORY(15827): jMEM M:65536, U:45632, A:19904, C:8100, clearScene, AFTER TRASH COLLECTOR
04-02 22:38:19.866: I/MEMORY(15827): jMEM M:65536, U:45632, A:19904, C:0, loadScene, ADDED IMAGE b:1, s:6, id:0
04-02 22:38:21.326: I/MEMORY(15827): jMEM M:65536, U:45632, A:19904, C:0, clearScene, CLEARED VIEW id:0
04-02 22:38:21.356: I/MEMORY(15827): jMEM M:65536, U:21300, A:44236, C:24332, clearScene, AFTER TRASH COLLECTOR
04-02 22:38:21.906: I/MEMORY(15827): jMEM M:65536, U:29404, A:36132, C:-8104, loadScene, ADDED IMAGE b:1, s:7, id:0
04-02 22:38:24.376: I/MEMORY(15827): jMEM M:65536, U:29404, A:36132, C:0, clearScene, CLEARED VIEW id:0
04-02 22:38:24.406: I/MEMORY(15827): jMEM M:65536, U:29404, A:36132, C:0, clearScene, AFTER TRASH COLLECTOR
04-02 22:38:24.916: I/MEMORY(15827): jMEM M:65536, U:29404, A:36132, C:0, loadScene, ADDED IMAGE b:1, s:8, id:0
04-02 22:38:25.496: I/MEMORY(15827): jMEM M:65536, U:37548, A:27988, C:-8144, loadScene, ADDED IMAGE b:1, s:8, id:1
04-02 22:38:25.796: I/MEMORY(15827): jMEM M:65536, U:45652, A:19884, C:-8104, loadScene, ADDED IMAGE b:1, s:8, id:2
04-02 22:38:28.356: I/MEMORY(15827): jMEM M:65536, U:45652, A:19884, C:0, clearScene, CLEARED VIEW id:2
04-02 22:38:28.356: I/MEMORY(15827): jMEM M:65536, U:45652, A:19884, C:0, clearScene, CLEARED VIEW id:1
04-02 22:38:28.356: I/MEMORY(15827): jMEM M:65536, U:45652, A:19884, C:0, clearScene, CLEARED VIEW id:0
04-02 22:38:28.376: I/MEMORY(15827): jMEM M:65536, U:45652, A:19884, C:0, clearScene, AFTER TRASH COLLECTOR
04-02 22:38:28.846: I/MEMORY(15827): jMEM M:65536, U:45652, A:19884, C:0, loadScene, ADDED IMAGE b:1, s:9, id:0
04-02 22:38:29.926: I/MEMORY(15827): jMEM M:65536, U:45652, A:19884, C:0, clearScene, CLEARED VIEW id:0
04-02 22:38:29.956: I/MEMORY(15827): jMEM M:65536, U:29400, A:36136, C:16252, clearScene, AFTER TRASH COLLECTOR
04-02 22:38:30.416: I/MEMORY(15827): jMEM M:65536, U:29400, A:36136, C:0, loadScene, ADDED IMAGE b:1, s:10, id:0
04-02 22:38:31.446: I/MEMORY(15827): jMEM M:65536, U:29400, A:36136, C:0, clearScene, CLEARED VIEW id:0
04-02 22:38:31.476: I/MEMORY(15827): jMEM M:65536, U:21300, A:44236, C:8100, clearScene, AFTER TRASH COLLECTOR
04-02 22:38:31.966: I/MEMORY(15827): jMEM M:65536, U:29404, A:36132, C:-8104, loadScene, ADDED IMAGE b:1, s:11, id:0
04-02 22:38:32.226: I/MEMORY(15827): jMEM M:65536, U:37548, A:27988, C:-8144, loadScene, ADDED IMAGE b:1, s:11, id:1
04-02 22:38:32.526: I/MEMORY(15827): jMEM M:65536, U:45652, A:19884, C:-8104, loadScene, ADDED IMAGE b:1, s:11, id:2
04-02 22:38:32.816: I/MEMORY(15827): jMEM M:65536, U:53756, A:11780, C:-8104, loadScene, ADDED IMAGE b:1, s:11, id:3
04-02 22:38:34.396: I/MEMORY(15827): jMEM M:65536, U:53756, A:11780, C:0, clearScene, CLEARED VIEW id:3
04-02 22:38:34.396: I/MEMORY(15827): jMEM M:65536, U:53756, A:11780, C:0, clearScene, CLEARED VIEW id:2
04-02 22:38:34.396: I/MEMORY(15827): jMEM M:65536, U:53756, A:11780, C:0, clearScene, CLEARED VIEW id:1
04-02 22:38:34.396: I/MEMORY(15827): jMEM M:65536, U:53756, A:11780, C:0, clearScene, CLEARED VIEW id:0
04-02 22:38:34.426: I/MEMORY(15827): jMEM M:65536, U:53756, A:11780, C:0, clearScene, AFTER TRASH COLLECTOR
04-02 22:38:34.886: I/MEMORY(15827): jMEM M:65536, U:53756, A:11780, C:0, loadScene, ADDED IMAGE b:2, s:0, id:0
04-02 22:38:35.776: I/MEMORY(15827): jMEM M:65536, U:53756, A:11780, C:0, clearScene, CLEARED VIEW id:0
04-02 22:38:35.816: I/MEMORY(15827): jMEM M:65536, U:21300, A:44236, C:32456, clearScene, AFTER TRASH COLLECTOR
04-02 22:38:36.256: I/MEMORY(15827): jMEM M:65536, U:29404, A:36132, C:-8104, loadScene, ADDED IMAGE b:2, s:1, id:0
04-02 22:38:36.976: I/MEMORY(15827): jMEM M:65536, U:29404, A:36132, C:0, clearScene, CLEARED VIEW id:0
04-02 22:38:37.006: I/MEMORY(15827): jMEM M:65536, U:29404, A:36132, C:0, clearScene, AFTER TRASH COLLECTOR
04-02 22:38:37.436: I/MEMORY(15827): jMEM M:65536, U:29404, A:36132, C:0, loadScene, ADDED IMAGE b:2, s:2, id:0
04-02 22:38:37.816: I/MEMORY(15827): jMEM M:65536, U:37548, A:27988, C:-8144, loadScene, ADDED IMAGE b:2, s:2, id:1
04-02 22:38:44.986: I/MEMORY(15827): jMEM M:65536, U:37532, A:28004, C:16, clearScene, CLEARED VIEW id:1
04-02 22:38:44.986: I/MEMORY(15827): jMEM M:65536, U:37532, A:28004, C:0, clearScene, CLEARED VIEW id:0
04-02 22:38:45.016: I/MEMORY(15827): jMEM M:65536, U:37532, A:28004, C:0, clearScene, AFTER TRASH COLLECTOR
04-02 22:38:45.496: I/MEMORY(15827): jMEM M:65536, U:37532, A:28004, C:0, loadScene, ADDED IMAGE b:2, s:3, id:0
04-02 22:38:45.996: I/MEMORY(15827): jMEM M:65536, U:45636, A:19900, C:-8104, loadScene, ADDED IMAGE b:2, s:3, id:1
04-02 22:38:48.306: I/MEMORY(15827): jMEM M:65536, U:45636, A:19900, C:0, clearScene, CLEARED VIEW id:1
04-02 22:38:48.306: I/MEMORY(15827): jMEM M:65536, U:45636, A:19900, C:0, clearScene, CLEARED VIEW id:0
04-02 22:38:48.336: I/MEMORY(15827): jMEM M:65536, U:45636, A:19900, C:0, clearScene, AFTER TRASH COLLECTOR
04-02 22:38:48.846: I/MEMORY(15827): jMEM M:65536, U:45636, A:19900, C:0, loadScene, ADDED IMAGE b:2, s:4, id:0
04-02 22:38:49.326: I/MEMORY(15827): jMEM M:65536, U:45636, A:19900, C:0, loadScene, ADDED IMAGE b:2, s:4, id:1
04-02 22:38:49.856: I/MEMORY(15827): jMEM M:65536, U:53740, A:11796, C:-8104, loadScene, ADDED IMAGE b:2, s:4, id:2
04-02 22:38:50.386: I/MEMORY(15827): jMEM M:65536, U:61844, A:3692, C:-8104, loadScene, ADDED IMAGE b:2, s:4, id:3
04-02 22:38:59.486: I/MEMORY(15827): jMEM M:65536, U:61832, A:3704, C:12, clearScene, CLEARED VIEW id:3
04-02 22:38:59.486: I/MEMORY(15827): jMEM M:65536, U:61832, A:3704, C:0, clearScene, CLEARED VIEW id:2
04-02 22:38:59.486: I/MEMORY(15827): jMEM M:65536, U:61832, A:3704, C:0, clearScene, CLEARED VIEW id:1
04-02 22:38:59.486: I/MEMORY(15827): jMEM M:65536, U:61832, A:3704, C:0, clearScene, CLEARED VIEW id:0
04-02 22:38:59.516: I/MEMORY(15827): jMEM M:65536, U:61832, A:3704, C:0, clearScene, AFTER TRASH COLLECTOR
04-02 22:38:59.936: I/MEMORY(15827): jMEM M:65536, U:61832, A:3704, C:0, loadScene, ADDED IMAGE b:2, s:5, id:0
04-02 22:39:00.356: I/MEMORY(15827): jMEM M:65536, U:61832, A:3704, C:0, loadScene, ADDED IMAGE b:2, s:5, id:1

我参加了
的“有效显示位图”培训 http://developer.android.com/training/displaying-bitmaps/index.html

我也经历过以下 stackoverflow 问题:
Recycle ImageView's Bitmap
ImageView: automatically recycle bitmap if ImageView is not visible (within ScrollView)
android - out of memory exception when creating bitmap
Bitmap decodeStream OutOfMemory Exception
Detect application heap size in Android
android createBitmap OOM when ((freeMemory > bitmapSize) && (nativeFreeHeap < bitmap size))
android 495KB image taking 10MB of Heap size
Android ImageView setImageBitmap
Android Memory Leak solution
Android custom view Bitmap memory leak

网络上还有更多文章!

澄清一下,这似乎只发生在我的 Nexus 7 中。我没有在我的模拟器或我的 Galaxy Nexus 上遇到过这个问题。我认为这可能是因为我正在缩放图像。

请帮我检测内存泄漏的位置!

***编辑(2013 年 4 月 2 日)请帮助我确定为什么来自运行 Android 10 (2.3.3) 的模拟器的日志显示系统分配内存和垃圾然后完全按照应有的方式清除,以及来自运行 Android 17 (4.2) 的 Nexus 7 的日志显示系统分配内存和垃圾收集器明显随机清除内存?

最佳答案

我无法确定为什么内存分配和收集在不同平台之间不同,但我能够通过缩小图像以适应可用内存来缓解问题并防止我的应用程序在任何平台上崩溃。

第一个函数确定位图内存的存储位置( native 或 Java),然后计算剩余可用内存(以 KB 为单位)。

private long calcAvailableMemory()
{
    long value = Runtime.getRuntime().maxMemory();
    String type = "";
    if (android.os.Build.VERSION.SDK_INT >= 11)
    {
        value = value / 1024) - (Runtime.getRuntime().totalMemory() / 1024);
        type = "JAVA";
    }
    else
    {
        value = value / 1024) - (Debug.getNativeHeapAllocatedSize() / 1024);
        type = "NATIVE";
    }
    Log.i(TAG, "calcAvailableMemory, size = " + value + ", type = " + type);
    return value;
}

第二个函数创建一个 ImageView 以附加到布局。 Show 对象包含我需要初始化 ImageView 的不同变量,例如尺寸和文件路径等。长 maxImageMemory 派生自第一个函数,然后除以我附加到布局的 View 数,得到最大数量分配每个位图的内存。

private ImageView newImage(Show show, long maxImageMemory)
{
    ImageView iv = new ImageView(this);
    String filePath = comin.generateFilePath(show);
    Bitmap bmp = scaleBitmap(filePath, maxImageMemory);
    Log.i(TAG, "newImage, id:" + show.id + ", file:" + filePath + ", x:" + bmp.getWidth() + ", y:" + bmp.getHeight());
    iv.setImageBitmap(bmp);
    iv.setScaleType(ImageView.ScaleType.FIT_XY);
    iv.setId(show.id);

    //set visibility
    if (show.visible)
        iv.setVisibility(View.VISIBLE);
    else
        iv.setVisibility(View.INVISIBLE);

    //set dimensions
    int width = (app.getWidth() * show.dimX) / 100;
    int height = (app.getHeight() * show.dimY) / 100;
    RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(width, height);
    iv.setLayoutParams(rlp);

    return iv;
}  

第三个函数缩放将加载到在函数 2 中创建的 ImageView 中的位图。while 循环是重要的部分,这是我增加样本大小的地方,直到位图所需的内存小于最大值内存可用。

private Bitmap scaleBitmap(String path, long maxImageMemory)
{
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(path, options);

    int sample = 1;
    //Scale image to screen resolution
    if (options.outHeight > app.getHeight() || options.outWidth > app.getWidth())
    {
        int heightRatio = Math.round((float) options.outHeight / (float) app.getHeight());
        int widthRatio = Math.round((float) options.outWidth / (float) app.getWidth());
        sample = heightRatio < widthRatio ? heightRatio : widthRatio;
    }

    //Scale image to stay within memory limitations
    while (calcBitmapSize(options.outWidth, options.outHeight, sample) > maxImageMemory)
    {
        sample++;
    }

    options.inSampleSize = sample;
    options.inPurgeable = true;
    options.inInputShareable = true;
    options.inJustDecodeBounds = false;

    Log.i(TAG, "scaleBitmap, scaleSample = " + sample);
    return BitmapFactory.decodeFile(path, options);
}  

这第四个函数根据原始分辨率以及建议的样本大小计算位图所需的内存量。

private long calcBitmapSize(int width, int height, int sample)
{
    long value = ((width/sample) * (height/sample) * 4) / 1024;
    Log.i(TAG, "calcBitmapSize, size = " + value);
    return value;
}  

最后,我开发了这个功能来帮助解决所有这些内存问题。它根据您运行的 Android 版本记录内存使用情况。

private void logMemory(String callingFunction)
{
    long max = Runtime.getRuntime().maxMemory() / 1024;

    if (debugJavaMemory)
    {
        long used = Runtime.getRuntime().totalMemory() / 1024;
        long available = max - used;
        long change = available - availableJavaMemoryOld;
        if (availableJavaMemoryOld != 0)
            Log.i(TAG_MEMORY, "jMEM M:" + max + ", U:" + used + ", A:" + available + ", C:" + change + ", " + callingFunction);
        availableJavaMemoryOld = available;
    }
    else if (debugNativeMemory)
    {
        long used = Debug.getNativeHeapAllocatedSize() / 1024;
        long available = max - used;
        long change = available - availableNativeMemoryOld;
        if (availableNativeMemoryOld != 0)
            Log.i(TAG_MEMORY, "nMEM M:" + max + ", U:" + used + ", A:" + available + ", C:" + change + ", " + callingFunction);
        availableNativeMemoryOld = available;
    }
}

关于Android 位图内存问题 - 错误 : Out of memory on a 8294416-byte allocation,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15756221/

相关文章:

c++ - 在图片控件中使用 SS_REALSIZECONTROL 时出现语法错误

java - Android 中的位图内存管理

android - 缩放图像以填充 ImageView 宽度并保持纵横比

android - 使用淡入淡出动画更改图像

java - 我应该将 CSV json 字符串转换为 int java 成员什么类型

android - 当我设置 Custom buildTypes 时,我遇到了一些错误。谁能帮助我?

android - 无法在android中使用mediacontroller暂停/前进/后退视频

android - 如何在 Android 中阻止特定的 url

c# - 为 Format32bppArgb 设置 Alpha 值

android - 更改 ListView 或回收 View 的单个项目的布局