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