Tracking memory leak - bitmaps - android

I have problem with tracking mmemory leak in my app.
I'm using MAT to do this, but i'm also beginner in this feature so i need your help.
Dominator tree looks like this:
Obviously 23% for bitmap isn't normal...
Path to GC Root -> exclude weak references:
But I really don't know what to do next ... It is obvious that memory is leaking through the images.
I'm converting resources to Bitmaps and scale it like this:
private Bitmap getBitmapFromRes(int resId) {
Bitmap tmp = null;
Bitmap b = null;
try {
// Decode image size
final int REQUIRED_SIZE = 70;
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
int scale = 1;
while (o.outWidth / scale / 2 >= REQUIRED_SIZE
&& o.outHeight / scale / 2 >= REQUIRED_SIZE)
scale *= 2;
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
InputStream fis = context.getResources().openRawResource(resId);
b = BitmapFactory.decodeStream(fis, null, o2);
fis.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (tmp != null) {
tmp.recycle();
tmp = null;
}
}
return b;
}
Thanks for help and sorry for my english...

Related

Android - Application crashes with Out Of Memory when selecting very large image [duplicate]

This question already has answers here:
Strange OutOfMemory issue while loading an image to a Bitmap object
(44 answers)
Closed 7 years ago.
In below code, I am getting exception "Out of memory on a byte allocation" for a large size images in function "getScaledBitmap" when processing decodeFile second time in code. This all below function is being called 4 times, as I am processing 4 different images on a screen.
Please guide on this.
private Bitmap processimage(String picturePath){
Bitmap thumbnail =null;
thumbnail=getScaledBitmap(picturePath,500,500);
Matrix matrix = null;
try {
ExifInterface exif = new ExifInterface(picturePath);
int rotation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
int rotationInDegrees = bal.exifToDegrees(rotation);
matrix = new Matrix();
if (rotation != 0f) {
matrix.preRotate(rotationInDegrees);
thumbnail=Bitmap.createBitmap(thumbnail, 0,0, thumbnail.getWidth(), thumbnail.getHeight(), matrix, true);
}
} catch (IOException e) {
e.printStackTrace();
}catch (Exception e) {
e.printStackTrace();
}
return thumbnail;
}
protected Bitmap getScaledBitmap(String picturePath, int width, int height) {
Bitmap result=null;
try{
BitmapFactory.Options sizeOptions = new BitmapFactory.Options();
sizeOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(picturePath, sizeOptions);
int inSampleSize = calculateInSampleSize(sizeOptions, width, height);
sizeOptions.inJustDecodeBounds = false;
sizeOptions.inSampleSize = inSampleSize;
result=BitmapFactory.decodeFile(picturePath, sizeOptions);
}catch(Exception ex){
ex.printStackTrace();
}
return result;
}
protected int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
while ((halfHeight / inSampleSize) > reqHeight
|| (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
public int exifToDegrees(int exifOrientation) {
if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_90) { return 90; }
else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_180) { return 180; }
else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_270) { return 270; }
return 0;
}
to scale image and to catch oom error I use the following code(but for one image).I am not sure if it will be ok for you..and include try catch for OOM in your code to avoid crash
Options options = new BitmapFactory.Options();
try{
options.inScaled = false;
options.inDither = false;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
imgBitmap=decodeFile(file);
}
catch(OutOfMemoryError e){
System.out.println("out of memory");
flag=1;
System.out.println("clearing bitmap????????????");
if (imgBitmap!=null) {
this.setBackgroundResource(0);
this.clearAnimation();
imgBitmap.recycle();
imgBitmap = null;}
// }
}
method to optimize imagefile
public Bitmap decodeFile(File f) {
try {
// decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
o.inDither=false; //Disable Dithering mode
o.inPurgeable=true; //Tell to gc that whether it needs free memory, the Bitmap can be cleared
o.inInputShareable=true;
o.inPreferredConfig = Bitmap.Config.ARGB_8888;
//Which kind of reference will be used to recover the Bitmap data after being clear, when it will be used in the future
o.inTempStorage=new byte[16*1024];
BitmapFactory.decodeStream(new FileInputStream(f), null, o);
// Find the correct scale value. It should be the power of 2.
int REQUIRED_SIZE = 300;
int width_tmp = o.outWidth, height_tmp = o.outHeight;
if(REQUIRED_SIZE > width_tmp)
REQUIRED_SIZE = width_tmp;
int scale = 1;
while (true) {
if (width_tmp / 2 < REQUIRED_SIZE
|| height_tmp / 2 < REQUIRED_SIZE)
break;
width_tmp /= 2;
height_tmp /= 2;
scale *= 2;
System.out.println(scale+"______________________________-");
}
// decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inDither=false;
o2.inScaled = false;
o2.inPurgeable=true; //Tell to gc that whether it needs free memory, the Bitmap can be cleared
o2.inInputShareable=true;
//Which kind of reference will be used to recover the Bitmap data after being clear, when it will be used in the future
o2.inTempStorage=new byte[24*1024];
o2.inSampleSize = 2;
o2.outWidth = width_tmp;
o2.outHeight = height_tmp;
o2.inPreferredConfig = Bitmap.Config.ARGB_8888;
try {
BitmapFactory.Options.class.getField("inNativeAlloc").setBoolean(o2,true);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
o2.inJustDecodeBounds = false;
return BitmapFactory.decodeStream(new FileInputStream(f), null,
o2);
}
catch (FileNotFoundException e) {
System.out.println("file not found");
}
return null;
}
On many phones, an application has enough RAM for exactly 1 (one) image, loading the 2nd one always results in out-of-memory exception. Even if you can load 2 photos in RAM on your phone, another phone will have a better camera and it will fail. If you want to display large images on the screen, you have to scale them.
And if you want to, say, merge two large images, well, you have a problem. I'd suggest doing this in a separate process (either a command line tool or a service). Note that the application can ask for large heap in the manifest: android:largeHeap=["true" | "false"] (link). But most likely you can just avoid loading two images in RAM.

NullPointerException rescaling bitmap from file Android

I'm facing this problem since a month with no solution:
I need to convert a file into a bitmap and rescaling it.
I'm using the following method, taken from android guide: Loading Large Bitmaps Efficiently
public Bitmap decodeSampledBitmapFromFile(String path, int reqSize) {
// First decode with inJustDecodeBounds=true to check dimensions
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
options.inMutable = true;
BitmapFactory.decodeFile(path, options);
// Calculate inSampleSize
double ratio = (double) options.outHeight / options.outWidth;
boolean portrait = true;
if (ratio < 1) {
portrait = false;
}
double floatSampleSize = options.outHeight / (double)reqSize;
options.inSampleSize = (int) Math.floor(floatSampleSize);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
Bitmap resultBitmap = BitmapFactory.decodeFile(path, options);
if(floatSampleSize % options.inSampleSize != 0){
if(portrait) {
resultBitmap = Bitmap.createScaledBitmap(resultBitmap, (int)(reqSize/ratio), reqSize, true);
} else {
resultBitmap = Bitmap.createScaledBitmap(resultBitmap, reqSize, (int)(ratio*reqSize), true);
}
}
return resultBitmap;
}
I've got the same NullPointerException but i can't reproduce it:
NullPointerException (#Utilities:decodeSampledBitmapFromFile:397) {AsyncTask #2}
NullPointerException (#Utilities:decodeSampledBitmapFromFile:399) {AsyncTask #3}
lines 397 and 399 are:
resultBitmap = Bitmap.createScaledBitmap(resultBitmap, (int)(reqSize/ratio), reqSize, true);
resultBitmap = Bitmap.createScaledBitmap(resultBitmap, reqSize, (int)(ratio*reqSize), true);
in this device models:
ST21a
U9500
M7
U8950-1
GT-I9305
Someone can help me to solve this?
is BitmapFactory.decodeFile returns null?
thank you so much
Try this hope works for you
public Bitmap decodeFile(String path, int reqSize) {
try {
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, o);
// The new size we want to scale to
final int REQUIRED_SIZE = reqSize;
// Find the correct scale value. It should be the power of 2.
int scale = 1;
while (o.outWidth / scale / 2 >= REQUIRED_SIZE && o.outHeight / scale / 2 >= REQUIRED_SIZE)
scale *= 2;
// Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
return BitmapFactory.decodeFile(path, o2);
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}

Out of Memory Error Bitmap With ImageView In Android 4.0 and Above

I am Getting error on my code : Out of Memory Error
Below is my code :
public class ViewFullImage extends Activity {
//Bitmap bitmap;
private Bitmap bitmap;
private ImageView iv;
private String ImgFile_Name;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.view_draw_picture);
Log.v("","===================== viewFullImage.java================");
try{
String path = "mfc/cam_img/";
int s_id=getIntent().getIntExtra("s_id", -1);
int intentKey=getIntent().getIntExtra("iv", -1);
iv = (ImageView)findViewById(R.id.iv_display);
File Dir= Environment.getExternalStorageDirectory();
File imageDirectory = new File(Dir,path);
File file = new File(imageDirectory, "img_"+s_id+"_"+intentKey+".jpg");
ImgFile_Name = file.getAbsolutePath();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = false;
options.inSampleSize = 1;
BitmapFactory.decodeFile(file.getAbsolutePath(),options);
int h = options.outHeight;
int w = options.outWidth;
Log.v("","This is h : "+h);
Log.v("","This is w : "+w);
bitmap = BitmapFactory.decodeFile(ImgFile_Name,options);
iv = (ImageView)findViewById(R.id.image);
if(h<w)
{
iv.setImageBitmap(rotateBitmap(bitmap));
}
else{
iv.setImageBitmap(bitmap);
}
}catch (Exception e) {
// TODO: handle exception
Log.v("","Exception : "+e);
}
}
Bitmap rotateBitmap(Bitmap bitmap)
{
Matrix matrix = new Matrix();
matrix.postRotate(90);
Bitmap bitmap1 = Bitmap.createBitmap(bitmap, 0, 0,
bitmap.getWidth(), bitmap.getHeight(),
matrix, true);
bitmap.recycle();
bitmap=null;
return bitmap1;
}
}
In this class i am trying to displaying image from sdcard. I am calling this Activity from other activities Like :
Intent intent =new Intent(cxt,ViewFullImage.class);
intent.putExtra("iv", 8);
intent.putExtra("s_id", s_id);
startActivity(intent);
Please somebody tell where i m doing mistack.....
You aren't doing anything wrong, you can't just allocate an image (or even a large string) in Android without knowing if it's going to fit in memory.
The problem happens in Android 4 devices because there is more 4.0 devices out there with only 16MB heaps. The memory heap is the memory where you will open your image in.
To solve this issue you should scale your image if required (depending both on the heap size and image size). Below is the code for how to decode with scaling:
public static Bitmap decodeSampleImage(File f, int width, int height) {
try {
System.gc(); // First of all free some memory
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f), null, o);
// The new size we want to scale to
final int requiredWidth = width;
final int requiredHeight = height;
// Find the scale value (as a power of 2)
int sampleScaleSize = 1;
while (o.outWidth / sampleScaleSize / 2 >= requiredWidth && o.outHeight / sampleScaleSize / 2 >= requiredHeight)
sampleScaleSize *= 2;
// Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = sampleScaleSize;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (Exception e) {
Log.d(TAG, e.getMessage()); // We don't want the application to just throw an exception
}
return null;
}
The other thing is, if you don't free some memory (System.gc()) and you click/switch between many pictures you may run out of memory anyway. If you run out of memory you don't want to blow the app, instead manage the case where the Bitmap is null. You can improve the Exception's catch cases for that as well.
Hope it helps.

How to increase the image quality in android..?

I am doing a "Image Editor" like application. I used default camera intent to capture the image. I used to parse the URI and set that to the image view like the following:
imgCaptured.setImageURI(Uri.parse(filePath));
If I use this raw image, occasionally it is throwing me out of memory error! So I decided to decode the image using the following:
"Got from stackoverflow"
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
preview_bitmap = BitmapFactory.decodeStream(is, null, options);
private Bitmap decodeFile(File f) {
try {
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f), null, o);
// The new size we want to scale to
final int REQUIRED_SIZE = 95;
// Find the correct scale value. It should be the power of 2.
int scale = 1;
while (o.outWidth / scale / 2 >= REQUIRED_SIZE
&& o.outHeight / scale / 2 >= REQUIRED_SIZE)
scale *= 2;
// Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {
}
return null;
}
If I use the decoded image, the output is not in good quality. Some how it seems to be blur. I want a good clear image! After setting it into the ImageView. I need to drag and drop another views.
How can I achieve the above?
What is a good way to do this?
what is the reason to divide by 2 in the loop ?
try this
while (o.outWidth / scale >= REQUIRED_SIZE
&& o.outHeight / scale >= REQUIRED_SIZE)
Probably You also would like to scale the image to the view's size with this method
http://developer.android.com/reference/android/graphics/Bitmap.html#createScaledBitmap(android.graphics.Bitmap, int, int, boolean)
change options.inSampleSize = 8 to options.inSampleSize = 4.
The method which you had used is not complete, you have to add few Math functions to, too maintain the quality of the image.
private static Bitmap decodeFile(File f) {
Bitmap b = null;
final int IMAGE_MAX_SIZE = 100;
try {
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
FileInputStream fis = new FileInputStream(f);
BitmapFactory.decodeStream(fis, null, o);
fis.close();
int scale = 1;
if (o.outHeight > IMAGE_MAX_SIZE || o.outWidth > IMAGE_MAX_SIZE) {
scale = (int) Math.pow(
2.0,
(int) Math.round(Math.log(IMAGE_MAX_SIZE
/ (double) Math.max(o.outHeight, o.outWidth))
/ Math.log(0.5)));
}
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
fis = new FileInputStream(f);
b = BitmapFactory.decodeStream(fis, null, o2);
fis.close();
} catch (Exception e) {
Log.v("Exception in decodeFile() ", e.toString() + "");
}
return b;
}
Please let me know, if it worked for you...!!!!:)

Outofmemory error in bitmap runtime exception

i am displaying my images from assests/image folder ,
but this code is not working . this code display images from assets folder in gallery . i am using gallery prefine library or jar file.
please expert check it . thank u
AssetManager assetManager = getAssets();
String[] files = null;
try {
files = assetManager.list("image");
} catch (IOException e) {
Log.e("tag", e.getMessage());
}
for(String filename : files) {
System.out.println("File name => "+filename);
InputStream in = null;
try {
ImageViewTouch imageView = new ImageViewTouch(Rahul.this);
imageView.setLayoutParams(new Gallery.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
final Options options = new Options();
options.outHeight = (int) scaleHeight;
options.outWidth = (int) scaleWidth;
options.inScaled = true;
options.inPurgeable = true;
options.inSampleSize = 2;
in = assetManager.open("image/"+filename);
Bitmap bit=BitmapFactory.decodeStream(in);
imageView.setImageBitmap(bit);
} catch(Exception e) {
Log.e("tag", e.getMessage());
}
}
gallery.setAdapter(arrayAdapter);
Hey please check my answer on the same issue: bitmap size exceeds Vm budget error android
And also always try to use maximum options while dealing with bitmaps like this:
final Options options = new Options();
options.outHeight = (int) scaleHeight; // new smaller height
options.outWidth = (int) scaleWidth; // new smaller width
options.inScaled = true;
options.inPurgeable = true;
// to scale the image to 1/8
options.inSampleSize = 8;
bitmap = BitmapFactory.decodeFile(imagePath, options);
This might solve your problem.
1) try to use bitmap.recycle(); to release memory before setting a new bitmap to your images
BitmapDrawable drawable = (BitmapDrawable) myImage.getDrawable();
Bitmap bitmap = drawable.getBitmap();
if (bitmap != null)
{
bitmap.recycle();
}
2) if your images are too large scale down them:
public static Bitmap decodeFile(File file, int requiredSize) {
try {
// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(file), null, o);
// The new size we want to scale to
// Find the correct scale value. It should be the power of 2.
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 1;
while (true) {
if (width_tmp / 2 < requiredSize
|| height_tmp / 2 < requiredSize)
break;
width_tmp /= 2;
height_tmp /= 2;
scale *= 2;
}
// Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
Bitmap bmp = BitmapFactory.decodeStream(new FileInputStream(file),
null, o2);
return bmp;
} catch (FileNotFoundException e) {
} finally {
}
return null;
}
Update
something like this:
for(int i=0; i<it.size();i++) {
ImageViewTouch imageView = new ImageViewTouch(GalleryTouchTestActivity.this);
imageView.setLayoutParams(new Gallery.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
Options options = new Options();
options.inSampleSize = 2;
String photoURL = it.get(i);
BitmapDrawable drawable = (BitmapDrawable) imageView.getDrawable();
Bitmap bitmap = drawable.getBitmap();
if (bitmap != null)
{
bitmap.recycle();
}
bitmap = BitmapFactory.decodeFile(photoURL);
imageView.setImageBitmap(bitmap);
arrayAdapter.add(imageView);
}

Categories

Resources