I realised that when when I made a call to System.gc() right after the
bitmao..recycle() call the heap space  is getting returned to the VM
heap. But I have been reading about Garbage collection and it seems
that calling System.gc() is not a good programming practice. Is there
another way to make sure that the garbage collection happens right
after the bitmap is recycled? Would it be helpful to implement Weak
references for this scenario?


 to On Dec 19, 3:10 pm, shyama <shyama.asoka...@gmail.com> wrote:
> I know this question has been asked over and over again in these
> forums. But the reason I am posting it again is because I have nt
> received a clear answer to it. It would be great if someone could help
> me with this.
>
> I am current using opencv + android to make some simple app that will
> do image manipulation like edge, blur etc and display it using an
> imagebutton. The images are being loaded through the gallery. There
> are 3 buttons to blur, edge, and reset to original which will display
> the modified image on the image button. given below is my code.
>
>     package com.example;
>
>     import java.io.File;
>     import java.io.FileNotFoundException;
>     import java.io.IOException;
>     import java.io.RandomAccessFile;
>     import java.nio.Buffer;
>     import java.nio.MappedByteBuffer;
>     import java.nio.channels.FileChannel;
>     import java.nio.channels.FileChannel.MapMode;
>
>     import android.app.Activity;
>     import android.content.Intent;
>     import android.graphics.*;
>     import android.graphics.Bitmap.Config;
>     import android.net.Uri;
>     import android.os.Bundle;
>     import android.os.Debug;
>     import android.provider.MediaStore;
>     import android.util.Log;
>     import android.view.View;
>     import android.view.View.OnClickListener;
>     import android.widget.Button;
>     import android.widget.ImageButton;
>     import android.widget.ImageView;
>
>     import org.opencv.core.*;
>     import org.opencv.imgproc.*;
>     import org.opencv.android.*;
>     import org.opencv.highgui.*;
>
>     import dalvik.system.VMRuntime;
>
>     import android.graphics.Color;
>
>     public class ImageProcessing extends Activity implements
> View.OnClickListener{
>
>     private ImageButton choice;
>     private Button Blur;
>     private Button Canny;
>     private Button Reset;
>     Uri photoUri;
>     static private Bitmap bitmap;
>     static private Bitmap mutBitmap;
>
>     private static String TAG = "ImageProcessing";
>     private static int TAKE_GALLERY_REQUEST = 2;
>     /** Called when the activity is first created. */
>     @Override
>     public void onCreate(Bundle savedInstanceState) {
>     super.onCreate(savedInstanceState);
>     setContentView(R.layout.img);
>
>     choice = (ImageButton) findViewById(R.id.imagechoice);
>
>     Blur = (Button) findViewById(R.id.Blur);
>     Canny = (Button) findViewById(R.id.edge);
>     Reset = (Button) findViewById(R.id.reset);
>
>     choice.setOnClickListener(this);
>     Blur.setOnClickListener(this);
>     Canny.setOnClickListener(this);
>     Reset.setOnClickListener(this);
>
>     }
>     @Override
>     public void onClick(View v) {
>
>     if(v.getId() == R.id.imagechoice)
>     {
>      Intent pickPhoto = new Intent(Intent.ACTION_PICK);
>      pickPhoto.setType("image/*");
>      startActivityForResult(pickPhoto, TAKE_GALLERY_REQUEST);
>     }
>     if(v.getId() == R.id.Blur)
>     {
>
>       if(mutBitmap != null)
>         mutBitmap.recycle();
>       mutBitmap = bitmap.copy(Config.ARGB_8888, true);
>       choice.setImageBitmap(mutBitmap);
>       Mat mImg = Utils.bitmapToMat(mutBitmap);
>       Size ksize = new Size(15,15);
>       Imgproc.blur(mImg, mImg, ksize);
>       mutBitmap.recycle();
>       mutBitmap = Bitmap.createBitmap(mImg.cols(), mImg.rows(),
> Bitmap.Config.ARGB_8888);
>       Utils.matToBitmap(mImg, mutBitmap);
>       choice.setImageBitmap(mutBitmap);
>     }
>     if(v.getId() == R.id.edge)
>     {
>       if(mutBitmap != null)
>         mutBitmap.recycle();
>       mutBitmap = bitmap.copy(Config.ARGB_8888, true);
>       choice.setImageBitmap(mutBitmap);
>       Mat mImg = new Mat();
>       mImg = Utils.bitmapToMat(mutBitmap);
>
>       /**Converting to grayscale**/
>       Mat mGray = new Mat(mImg.rows(), mImg.cols(), CvType.CV_8UC1,
> new Scalar(0));
>       Imgproc.cvtColor(mImg , mGray, Imgproc.COLOR_BGRA2GRAY, 4);
>       /**Applying Canny**/
>       Imgproc.Canny(mGray, mGray, 80, 90);
>
>       //Converting back to 4 channel image
>       Imgproc.cvtColor(mGray , mImg, Imgproc.COLOR_GRAY2RGBA, 4);
>       mutBitmap.recycle();
>       mutBitmap = Bitmap.createBitmap(mImg.cols(), mImg.rows(),
> Bitmap.Config.ARGB_8888);
>       Utils.matToBitmap(mImg, mutBitmap);
>       choice.setImageBitmap(mutBitmap);
>     }
>     if(v.getId() == R.id.reset)
>     {
>       choice.setImageBitmap(bitmap);
>     }
>     }
>     @Override
>     protected void onPause() {
>     super.onPause();
>     Log.v(TAG,"on pause called");
>
>     Log.v(TAG,"Allocated memoryin on pause before recycle done:
>     "+Debug.getNativeHeapAllocatedSize());
>         choice.setImageBitmap(null);
>         if(bitmap != null)
>         {
>             Log.v(TAG,"bitmap is not null");
>             bitmap.recycle();
>             if(bitmap.isRecycled())
>                 Log.v(TAG,"bitmap is recycled");
>             bitmap = null;
>         }
>
>         if(mutBitmap != null)
>         {
>             mutBitmap.recycle();
>             if(mutBitmap.isRecycled())
>                 Log.v(TAG,"mutBitmap is recycled");
>             mutBitmap = null;
>         }
>         Log.v(TAG,"Allocated memory on pause after recycle done:  "
>         +Debug.getNativeHeapAllocatedSize());
>
>     }
>     @Override
>     protected void onResume() {
>         super.onResume();
>         choice.setImageBitmap(bitmap);
>
>     }
>     @Override
>     protected void onActivityResult(int requestCode, int resultCode,
>             Intent intent) {
>         super.onActivityResult(requestCode, resultCode, intent);
>         Log.v(TAG,"onActivityResult called before loading bitmap,
> Allocated
>         memory:  "+Debug.getNativeHeapAllocatedSize());
>
>         if (resultCode == RESULT_OK) {
>             photoUri  = intent.getData();
>
>             if (photoUri != null) {
>                 try {
>                      Log.v(TAG, "No crash 0");
>                      bitmap =
> Bitmap.createScaledBitmap(MediaStore.Images.Media.getBitmap(this
>                             .getContentResolver(), photoUri), 300,
> 400, true);
>                      Log.v(TAG, "No crash 1");
>                        Log.v(TAG,"onActivityResult called after
> loading bitmap,
>                        Allocated memory:
> "+Debug.getNativeHeapAllocatedSize());
>
>                      choice.setImageBitmap(bitmap);
>
>                 } catch (Exception e) {
>                     Log.v(TAG, "Unable to load image at path: " +
> photoUri.getPath());
>                 }
>             }
>         }
>
>     }
>
>     }
>
> bitmap - used for loading the image that user has selected from
> gallery
> mutBitmap - copy the image in bitmap and sets the mutable boolean to
> true. so that I can manipulate the image
>
> I have included calls to Debug.getNativeHeapAllocatedSize() at four
> places
> 1)In onPause() before I recycle the bitmap(onPause is called when the
> image button is clicked each time)
> 2) after bitmap.recycle() is called in onPause()
> 3) before new bitmap is loaded in onActivityResult()
> 4) after new bitmap is loaded in onActivityResult()
>
> the following are the results in log cat:
>
> >12-19 13:22:20.629: VERBOSE/ImageProcessing(4551): on pause called
> >12-19 13:22:20.629: VERBOSE/ImageProcessing(4551): Allocated memoryin on 
> >pause before recycle done:  5508024
> >12-19 13:22:20.629: VERBOSE/ImageProcessing(4551): Allocated memory on pause 
> >after recycle done:  5508096
> >12-19 13:22:39.279: VERBOSE/ImageProcessing(4551): onActivityResult called 
> >before loading bitmap, Allocated memory:  5507488
> >12-19 13:22:39.279: VERBOSE/ImageProcessing(4551): No crash 0
> >12-19 13:22:39.839: VERBOSE/ImageProcessing(4551): No crash 1
> >12-19 13:22:39.850: VERBOSE/ImageProcessing(4551): onActivityResult called 
> >after loading bitmap, Allocated memory:  18246120
> >12-19 13:22:51.329: VERBOSE/ImageProcessing(4551): on pause called
> >12-19 13:22:51.329: VERBOSE/ImageProcessing(4551): Allocated memoryin on 
> >pause before recycle done:  18246704
> >12-19 13:22:51.339: VERBOSE/ImageProcessing(4551): bitmap is not null
> >12-19 13:22:51.339: VERBOSE/ImageProcessing(4551): bitmap is recycled
> >12-19 13:22:51.339: VERBOSE/ImageProcessing(4551): Allocated memory on pause 
> >after recycle done:  18005032
> >12-19 13:23:04.779: VERBOSE/ImageProcessing(4551): onActivityResult called 
> >before loading bitmap, Allocated memory:  18004408
> >12-19 13:23:04.779: VERBOSE/ImageProcessing(4551): No crash 0
>
> As you can see, the second time I tried to load the same image the app
> crashed. In onPause(), the nativeheapsize allocatted before and after
> bitmap.recycle() is called is the same, even though bitma.isRecycled()
> gives true.
>
> I also did adb shell dumpsys meminfo and this is what I got:
>
> When the image is loaded:
>          ** MEMINFO in pid 3679 [com.example] **
>
>                     native   dalvik    other    total    limit
> bitmap nativeBmp
>
>             size:    19240     2743      N/A    21983    24576      N/
> A      N/A
>
>        allocated:    17871     2569      N/A    20440      N/A
> 12678        0
>
>             free:      360      174      N/A      534      N/A      N/
> A      N/A
>
>            (Pss):     1205     1048    16403    18656      N/A      N/
> A      N/A
>
>     (shared dirty):     1660     4260     1424     7344      N/A
> N/A      N/A
>
>     (priv dirty):     1168      832    15876    17876      N/A      N/
> A      N/A
>
>  When the button is clicked again to load another image(i.e. onpause()
> is called)
>               ** MEMINFO in pid 3679 [com.example] **
>
>                     native   dalvik    other    total    limit
> bitmap nativeBmp
>
>             size:    19240     2743      N/A    21983    24576      N/
> A      N/A
>
>        allocated:     5186     2487      N/A     7673      N/A
> 0        0
>
>             free:      361      256      N/A      617      N/A      N/
> A      N/A
>
>            (Pss):     1205     1048     3718     5971      N/A      N/
> A      N/A
>
>          (shared dirty):     1660     4260     1424     7344      N/
> A      N/A      N/A
>
>          (priv dirty):     1168      832     3192     5192      N/
> A      N/A      N/A
> As you can see the allocated native heap size is changing in meminfo
> when image is loaded and when onPause is called. But I am not sure why
> the nativeheapallocated function in code still shows the same value.
> I have 2 questions now:
> 1) where is bitmap memory allocated. What happens when recycle()
> function is called
> 2) What is the native referred to in meminfo and in the
> Debug.getNativeHeapAllocatedSize()? Are they different?
>
> If you think my approach is not the most effecient one I am also happy
> to change it.
>
> Thanks,
> Shyama

-- 
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to android-developers@googlegroups.com
To unsubscribe from this group, send email to
android-developers+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en

Reply via email to