Android:以编程方式释放位图内存资源

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20715442/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 03:20:41  来源:igfitidea点击:

Android: free up bitmap memory resources programmatically

androidmemorybitmapdialog

提问by pearmak

I am having a dialog where users can freely draw inside the dialog.

我有一个对话框,用户可以在对话框内自由绘图。

The dialog is extending a view, and the drawing area is created by

该对话框正在扩展视图,绘图区域由

bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);

However, the drawing need not to be kept, and when the user close the dialog and reopen again, his previous drawing is not needed to be kept and redraw from null.

但是,绘图不需要保留,当用户关闭对话框并重新打开时,不需要保留他之前的绘图并从空值重新绘制。

Detailed codes:

详细代码:

DoodleView:

涂鸦视图:

   // DoodleView constructor initializes the DoodleView
   public DoodleView(Context context, AttributeSet attrs) 
   {
      super(context, attrs); // pass context to View's constructor

      paintScreen = new Paint(); // used to display bitmap onto screen

      // set the initial display settings for the painted line
      paintLine = new Paint();
      paintLine.setAntiAlias(true); // smooth edges of drawn line
      paintLine.setColor(Color.BLACK); // default color is black
      paintLine.setStyle(Paint.Style.STROKE); // solid line
      paintLine.setStrokeWidth(25); // set the default line width
      paintLine.setStrokeCap(Paint.Cap.ROUND); // rounded line ends
      pathMap = new HashMap<Integer, Path>();
      previousPointMap = new HashMap<Integer, Point>();
   } // end DoodleView constructor

   // Method onSizeChanged creates BitMap and Canvas after app displays
   @Override
   public void onSizeChanged(int w, int h, int oldW, int oldH)
   {
      bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
      bitmapCanvas = new Canvas(bitmap);
      bitmap.eraseColor(Color.parseColor("#80FFFFFF")); // erase the BitMap with white
   } // end method onSizeChanged

   // clear the painting
   public void recycling()
   {
       bitmap.recycle();
   }

Writing board:

写字板:

public void write_board () 
{
    writing_dialog = new Dialog(Apple.this, android.R.style.Theme_Translucent_NoTitleBar);
    WindowManager.LayoutParams lp = writing_dialog.getWindow().getAttributes();
    lp.dimAmount = 0.5f;
    writing_dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);

    Window window = writing_dialog.getWindow();
    window.setGravity(Gravity.CENTER);

    writing_dialog.setContentView(R.layout.alert_drawing_pad);
    writing_dialog.setCancelable(true);
    writing_dialog.show();
    writing_dialog.setVolumeControlStream(AudioManager.STREAM_MUSIC);   

    doodleView = (DoodleView) writing_dialog.findViewById(R.id.doodleView);

        alert_close.setOnClickListener(new OnClickListener() 
        {
            public void onClick(View v) 
            {
                writing_dialog.dismiss();
                doodleView.recycling();
                return;
            }
        });

Question:

题:

I discover that after opening the dialog several times (7 to 8 times using Samsung Note2), the dialog would lag for a few second and the phone without response, and then further press again some while later, the dialog can appear again and everything is ok.

我发现打开对话框几次后(使用三星 Note2 7 到 8 次),对话框会延迟几秒钟,手机没有反应,然后再按一会儿,对话框又会出现,一切正常好的。

The logcat at this time reports E/OpenGLRenderer(25296): Out of memory!

此时的logcat报告 E/OpenGLRenderer(25296): Out of memory!

and it goes on without hanging for some time.

它会持续一段时间而不会挂。

Yet if further press out for the drawing board, it goes with a serious memory error and this time the system hangs.

然而,如果进一步按下绘图板,则会出现严重的内存错误,这次系统挂起。

FATAL EXCEPTION: main
java.lang.OutOfMemoryError
    at android.graphics.Bitmap.nativeCreate(Native Method)
    at android.graphics.Bitmap.createBitmap(Bitmap.java:726)
    at android.graphics.Bitmap.createBitmap(Bitmap.java:703)
    at android.graphics.Bitmap.createBitmap(Bitmap.java:670)
    at com.abc.abc.DoodleView.onSizeChanged(DoodleView.java:60)
    at android.view.View.sizeChange(View.java:15326)
    at android.view.View.setFrame(View.java:15290)
    at android.view.View.layout(View.java:15201)
    at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1076)
    at android.view.View.layout(View.java:15204)
    at android.view.ViewGroup.layout(ViewGroup.java:4793)
    at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1076)
    at android.view.View.layout(View.java:15204)
    at android.view.ViewGroup.layout(ViewGroup.java:4793)
    at android.widget.FrameLayout.onLayout(FrameLayout.java:448)
    at android.view.View.layout(View.java:15204)
    at android.view.ViewGroup.layout(ViewGroup.java:4793)
    at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1677)
    at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1531)
    at android.widget.LinearLayout.onLayout(LinearLayout.java:1440)
    at android.view.View.layout(View.java:15204)
    at android.view.ViewGroup.layout(ViewGroup.java:4793)
    at android.widget.FrameLayout.onLayout(FrameLayout.java:448)
    at android.view.View.layout(View.java:15204)
    at android.view.ViewGroup.layout(ViewGroup.java:4793)
    at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2263)
    at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2009)
    at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1251)
    at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6379)
    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:791)
    at android.view.Choreographer.doCallbacks(Choreographer.java:591)
    at android.view.Choreographer.doFrame(Choreographer.java:561)
    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:777)
    at android.os.Handler.handleCallback(Handler.java:730)
    at android.os.Handler.dispatchMessage(Handler.java:92)
    at android.os.Looper.loop(Looper.java:137)
    at android.app.ActivityThread.main(ActivityThread.java:5493)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:525)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1209)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1025)
    at dalvik.system.NativeStart.main(Native Method)

I have researched and added
bitmap.recycle();whenever the user closes the dialog. But it still reports the same error.


bitmap.recycle();每当用户关闭对话框时,我都会进行研究和添加。但它仍然报告同样的错误。

Are there any way to dispose the bitmap whenever the user closes the dialog?

每当用户关闭对话框时,有没有办法处理位图?

Thanks!

谢谢!

回答by Rizwan

You should call this on dismiss of your dialog

您应该在关闭对话时调用它

bitmap.recycle();
bitmap = null;

bitmap.recycle();releases the native heap that is used in bitmaps. And setting it to null is to assist the GC to quickly collect your reference.

bitmap.recycle();释放位图中使用的本机堆。并且设置为null是为了辅助GC快速收集你的引用。

回答by Brcinho

First invalidate the reference that canvas or any other object has to bitmap

首先使画布或任何其他对象对位图的引用无效

if (bitmapCanvas != null) {
    bitmapCanvas.setBitmap(null);
    bitmapCanvas = null;
}

Second release bitmap resources

第二次发布位图资源

if (bitmap != null) {
    bitmap.recycle();
    bitmap = null;
}

If needed, Third, keep the bitmap as WeakReference

如果需要,第三,保持位图为 WeakReference

WeakReference<Bitmap> bitmap;
if (bitmap != null) {
    bitmap.get().recycle();
    bitmap.clear();
    bitmap= null;
}

回答by broschb

It looks like there should only be one bitmap in memory at a time. A few thoughts.

看起来内存中一次应该只有一个位图。一些想法。

First when recycling the bitmap set it to null, also set the canvas to null. If this does not solve the issue, i would be curious to see the code you are using to actually paint the lines. Also getting a heap dump after invoking the dialog and closing it will show you which objects are still in memory, and allow you to quickly track down what is holding on to the bitmap, and it's kinda fun :)

首先在回收位图时将其设置为空,同时将画布设置为空。如果这不能解决问题,我很想看看您用于实际绘制线条的代码。在调用对话框并关闭它之后获得堆转储将向您显示哪些对象仍在内存中,并允许您快速跟踪保持位图的内容,这有点有趣:)

This postis a great start on investigating a heap dump if you have not done it before.

如果您以前没有做过堆转储,这篇文章是调查堆转储的一个很好的开始。

UPDATE

更新

To set the canvas to null, you can do something like this

要将画布设置为空,您可以执行以下操作

public void recycling()
{
   bitmap.recycle();
   bitmap = null;
   bitmapCanvas = null;
}

However upon closer inspection of your code, i see that you are creating a new dialog everytime and then dismissing the dialog. This will not free up the dialog from memory. Try updating your code so you only initialize the dialog if it is null.

但是,仔细检查您的代码后,我发现您每次都在创建一个新对话框,然后关闭该对话框。这不会从内存中释放对话框。尝试更新您的代码,以便仅在对话框为空时才初始化对话框。

public void write_board () 
 {
  if(writing_dialog == null){
    writing_dialog = new Dialog(Apple.this,         android.R.style.Theme_Translucent_NoTitleBar);
    WindowManager.LayoutParams lp = writing_dialog.getWindow().getAttributes();
    lp.dimAmount = 0.5f;
    writing_dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);

    Window window = writing_dialog.getWindow();
    window.setGravity(Gravity.CENTER);

    writing_dialog.setContentView(R.layout.alert_drawing_pad);
    writing_dialog.setCancelable(true);
    writing_dialog.setVolumeControlStream(AudioManager.STREAM_MUSIC);
 }
 //now do stuff with your dialog
 writing_dialog.show();


 doodleView = (DoodleView) writing_dialog.findViewById(R.id.doodleView);

回答by AJD

Bitmap memory issues a pretty common problem. Try out some of the solutions in this thread

位图内存问题是一个很常见的问题。尝试此线程中的一些解决方案

Strange out of memory issue while loading an image to a Bitmap object

将图像加载到位图对象时出现奇怪的内存不足问题