Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Picasso Library - Out of Memory

I am using Picasso library latest version 2.4.0 in my app for downloading and caching images. There are roughly 25-30 images of size 300KB-400KB each. I think that this is no way something big or heavy.

Even though the app is running fine, I'm getting out of memory allocations in my logcat. Can anyone explain why is this happening?

Code for loading images in GridView adapter:

Picasso.with(mContext).load(getUrl()).placeholder(R.drawable.placeholder)
            .into(viewholder.image);

Here is my Logcat output:

I/dalvikvm-heap(11142): Grow heap (frag case) to 53.860MB for 2720016-byte allocation
I/dalvikvm-heap(11142): Forcing collection of SoftReferences for 3265936-byte allocation
E/dalvikvm-heap(11142): Out of memory on a 3265936-byte allocation.
I/dalvikvm(11142): "Picasso-/images/posters/34.71.jpg" prio=5 tid=18 RUNNABLE
I/dalvikvm(11142):   | group="main" sCount=0 dsCount=0 obj=0x4283f248 self=0x60a47830
I/dalvikvm(11142):   | sysTid=11196 nice=10 sched=0/0 cgrp=apps/bg_non_interactive I/dalvikvm(11142):   | state=R schedstat=( 2070202497 1858185620 3947 ) utm=172 stm=35 core=3
I/dalvikvm(11142):   at android.graphics.Bitmap.nativeCreate(Native Method)
I/dalvikvm(11142):   at android.graphics.Bitmap.createBitmap(Bitmap.java:726)
I/dalvikvm(11142):   at android.graphics.Bitmap.createBitmap(Bitmap.java:703)
I/dalvikvm(11142):   at android.graphics.Bitmap.createBitmap(Bitmap.java:636)
I/dalvikvm(11142):   at com.squareup.picasso.BitmapHunter.transformResult(BitmapHunter.I/dalvikvm(11142):   at com.squareup.picasso.BitmapHunter.hunt(BitmapHunter.java:168)
I/dalvikvm(11142):   at com.squareup.picasso.BitmapHunter.run(BitmapHunter.java:111)
I/dalvikvm(11142):   at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:390I/dalvikvm(11142):   at java.util.concurrent.FutureTask.run(FutureTask.java:234)
I/dalvikvm(11142):   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.I/dalvikvm(11142):   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.I/dalvikvm(11142):   at java.lang.Thread.run(Thread.java:841)
I/dalvikvm(11142):   at com.squareup.picasso.Utils$PicassoThread.run(Utils.java:408)
I/dalvikvm-heap(11142): Forcing collection of SoftReferences for 3265936-byte allocation
E/dalvikvm-heap(11142): Out of memory on a 3265936-byte allocation.
I/dalvikvm(11142): "Picasso-/images/posters/34.71.jpg" prio=5 tid=17 RUNNABLE
I/dalvikvm(11142):   | group="main" sCount=0 dsCount=0 obj=0x42841b88 self=0x5ec91f90
I/dalvikvm(11142):   | sysTid=11183 nice=10 sched=0/0 cgrp=apps/bg_non_interactive I/dalvikvm(11142):   | state=R schedstat=( 2050467088 1713164574 3713 ) utm=172 stm=32 core=3
I/dalvikvm(11142):   at android.graphics.Bitmap.nativeCreate(Native Method)
I/dalvikvm(11142):   at android.graphics.Bitmap.createBitmap(Bitmap.java:726)
I/dalvikvm(11142):   at android.graphics.Bitmap.createBitmap(Bitmap.java:703)
I/dalvikvm(11142):   at android.graphics.Bitmap.createBitmap(Bitmap.java:636)
I/dalvikvm(11142):   at com.squareup.picasso.BitmapHunter.transformResult(BitmapHunter.I/dalvikvm(11142):   at com.squareup.picasso.BitmapHunter.hunt(BitmapHunter.java:168)
I/dalvikvm(11142):   at com.squareup.picasso.BitmapHunter.run(BitmapHunter.java:111)
I/dalvikvm(11142):   at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:390I/dalvikvm(11142):   at java.util.concurrent.FutureTask.run(FutureTask.java:234)
I/dalvikvm(11142):   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.I/dalvikvm(11142):   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.I/dalvikvm(11142):   at java.lang.Thread.run(Thread.java:841)
I/dalvikvm(11142):   at com.squareup.picasso.Utils$PicassoThread.run(Utils.java:408)
like image 775
Adeel Ahmad Avatar asked Nov 14 '14 20:11

Adeel Ahmad


3 Answers

Your original code was downloading the full image, loading the full image into memory, then having Android scale the image down to fit your ImageView.

In this case, you do not need the full image in memory -- you need something closer in size to what the ImageView is.

fit() on Picasso handles this. It uses inSampleSize on BitmapFactory.Options to downsample the image as it is being loaded into memory, to get you something around the size of the ImageView, letting Android scale from there. This will significantly reduce the memory footprint of each image, particularly depending on how big of an ImageView you are using.

like image 127
CommonsWare Avatar answered Nov 02 '22 01:11

CommonsWare


Watch out with .fit()!

Its better to server the right image sizes from the server, by sending device screen width to the server, and serving the right image for the device. In this way tou dont need todo scaling.

like image 1
TjerkW Avatar answered Nov 02 '22 00:11

TjerkW


All the others answers sounds good when mentioning .fit().

I think it can be interesting to mention downside of .fit though:

fit() is measuring the dimensions of the target ImageView and internally uses resize() to reduce the image size to the dimensions of the ImageView. There are two things to know about fit(). First, calling fit() can delay the image request since Picasso will need to wait until the size of the ImageView can be measured. Second, you only can use fit() with an ImageView as the target (we'll look at other targets later).

The advantage is that the image is at the lowest possible resolution, without affecting its quality. A lower resolution means less data to be hold in the cache. This can significantly reduce the impact of images in the memory footprint of your app. In summary, if you prefer a lower memory impact over a little faster loading times, fit() is a great tool.

TLDR:

  • Can only be used with ImageView targets
  • May slow down loading

Source: https://futurestud.io/tutorials/picasso-image-resizing-scaling-and-fit

like image 1
Simon Ninon Avatar answered Nov 02 '22 00:11

Simon Ninon