Picasso: heavy performance issue

Created on 18 May 2014  路  39Comments  路  Source: square/picasso

Hello guys!

I experienced a strange behavior if I try to load a couple 480x320 jpg file into a 100dp x 100dp imageviews (5-6 max on the screen in portrait mode) in a gridview, it is lagging heavily except if it comes from the cache itself. However when i'm trying to load much smaller pictures it is totally smooth. I'm 99% sure that is related to the cache because if i'm using the .skipMemoryCache() function it is much more better! This is happening on all device not just on my n5.

The library usage is not overly complicated.
Picasso.with(mContext).load(mModel.getImageLink()).into(mPreviewImage);

There are 4 more textviews next to the image in the cell. If'm not loading any images then it is totally okay. The overdraws are minimized everything is green and blue. The latest okhttp 1.5.4 is present. There could be 2000 elements in the adapter. I'm using your awesome library from the beginning and never experienced such a performance drop.

sample urls:
big
http://d1bko2jzh7ix12.cloudfront.net/5/c6c469346129c00b9c69b63d092a6f68/gm.jpg
small
http://d1bko2jzh7ix12.cloudfront.net/5/c6c469346129c00b9c69b63d092a6f68/t.jpg

Thanks in advance!

Cheers,
Gabor

Most helpful comment

am having same problem posted initially.. i have a pager viewer and a listview in each tab .. i have multiple rows and in each row there is an image... switching fragments from pager is laggy because of picasso..
Picasso.with(context).load(link).into(Image);

All 39 comments

You should always resize your images to the size of the target:

int dp100 = ... 
Picasso.with(mContext).load(mModel.getImageLink()).resize(dp100,dp100).into(mPreviewImage);

Unfortunately it works the same :( and blocking the UI thread

I forget to mentioned that it is happening mainly when i'm scrolling very fast.

I thought the same as well first and I double checked it (again) and everything has a precise height.

Maybe a traceview screenshot could help a little bit.
https://www.dropbox.com/s/ayxx2l535w9b8bv/Screen%20Shot%202014-05-18%20at%2014.43.14.png

this is the first 5 element order by EXCL CPU TIME

Thanks for the report. This is actually the decode of the bitmap that takes too long. Can you please provide a sample app for me so I can further investigate?

Thanks for the reply. Sadly i'm not allowed to send it, but i'll look after the possibilities. I'll get back go you soon. The other pictures are the same as I posted before.

There is a possibility that too many bitmaps load too quickly. I saw your URL is rather a small image.

We're also using a batch delay for picasso so thats also a bit surprising. Have you tried using a single thread executor? Just to ensure that this could be it?

I tried to create my Picasso instance with the following piece of code.
picasso = new Picasso.Builder(context).executor(Executors.newSingleThreadExecutor()).build();
Still the same.

I'll need to recreate a similar app to test it out.

How does the sample app work for you in terms of speed?

The screen that contains the problematic part has just a gridview with relative layout above. The information comes from an API which parsed by jackson json parser. The cells has 4 textviews and 3 images (2 are fixed icons) including the loaded part. If I comment out the image loading it is as smooth as possible without any hiccup.

For reference, we will have a ScrollListener mode in Picasso in version 2.4. This would allow you to scroll and not load images until scrolling has finished.

I know you obviously dont want to wait so I will be looking to see what I can do between that.

2.3 should be out next week and includes a few performance improvements.. I doubt collectively they would help in the overall experience you have.

Whoa! That will be an awesome feature. If i found any other clue i'll post it here immediately.

I think its just too many bitmaps loading quickly. Most of them are from disk so they are reloaded very very fast.

Do you have debug indicators enabled? Those would also slow down rendering.

Feel free to submit a PR for performance improvements.

One thing I've noticed is that performance issues almost always occur on tablets, but not on phones - despite having the same hardware / display resolution.

I've even tried to change the resolution / density using the adb shell wm size and adb shell wm density commands to see if there was any change, but nope. Anyone got any ideas why this might be?

Possibly more imageviews and more requests on screen, essentially creating a lot of GC.

There is a PR out there for this issue but I am on vacation currently. We will be tackling this for 2.4.

That was my first thought as well, but I've tested with the same amount and it's still a lot worse on tablets. Quite strange. Everything flies on my Nexus 5, not as much as a single frame drop.

Enjoy your vacation :-)

Hi,
I have worked on this issue (or at least on a similar issue) and I have made a pull request #561

Im just curious if my fix would solve your problem:
Could you try to use this SNAPSHOT version of my pull request https://db.tt/3l01sQXJ in your project. You simply have to add listView.setOnScrollListener( new PicassoScrollListener(context) ) if you use the default picasso instance (Picasso.with(context)) or listView.setOnScrollListener( new PicassoScrollListener(picasso) ) if you use a custom instance of picasso.

Sure thing, I'll give it a try :-)

It's definitely not loading images until scrolling stops, but I'm still experiencing quite a bit of lag on my tablet. I know for a fact that Picasso is causing it as all frames are less than 4 milliseconds to render without the Picasso call in getView().

On a side note, would it be possible to make it resume loading of images again once the fling velocity starts reaching zero? I.e. when the list / grid almost doesn't scroll anymore.

Thanks for trying. So no performance improvements? So I guess the GC will cause your performance issue. My fix, like you have already suggested, simply pause/resume Picassos internal dispatcher (no fading images while scrolling). So it has nothing to do with GC related topics.

Well, it would be possible to implement your own OnScrollListener (you simply have to call Picasso.interruptDispatching() and Picasso.continueDispatching() in your OnScrollListener) which tracks the speed of flinging. If the community wants to we could implement and add such a OnScrollListener. However, I think that if you really need PicassoScrollListener to achieve a good scroll performance (by suppressing fading while scrolling) then you don't want to resume until scrolling/flinging has finished completely. I guess that if you resume at velocity nearly zero the scroll performance would not be good (frames are skipped), but it would be worth to test it in practice.

Here's what it looks like when I scroll within an area that's been cached:
cached

As you can see, it works just fine. Everything's pretty good and Picasso handles the cached versions of the images quite well. No noteworthy process (red) or draw (blue) lag.

This, however, is what it looks like if I fling it fast in an area that's not been cached:
untitled-5

It seems like Picasso is trying to "catch up" with the requests. Lots of stuff is going on in the process and draw sections of the profiling overlay. Any ideas?

I can confirm that I have the same issue in my app. Im not sure why, because dispatching is disabled while scrolling. Probably the GC (I have also many images, not as many as you).

My "work around" is to trigger the picasso calls only if not scrolling. So I have an OnScrollListener in my list view and after scrolling is finished I will iterate over each visible cell in the ListView and do the picasso execute to load the images. The disadvantage is, that I set every ImageView manually to the placeholder ( without picasso with ImageView.setImageResource()) and that the memory cache is skiped (because I do not execute picasso) while scrolling. But the scroll performance is good

I haven't really looked into the source of Picasso's dispatcher, but if the dispatcher is interrupted, shouldn't image loading be interrupted as well? If image loading is indeed interrupted then it doesn't make sense that the GC would make such a mess. Like I said, it works flawlessly without the Picasso calls.

My implementation of the "dispatcher interruption" only interrupts the dispatching of the loaded image. So the http call will be executed and the bitmap will be loaded / decoded. Only the "dispatching" process will not be triggered, which means the thread who has loaded the image will not notify the main UI Thread that the image has been loaded successfully and can now fade in into the given imageview. However it looks like that interrupting the Image loading thread as well would be good addition.

Thought so. Yeah, that makes sense then. Honestly, just pausing the dispatcher is not a good solution at all then. There's literally no reason why Picasso should load images while flinging.

hm ... good point ... So as far as i know Picasso will cancel any running http request for a given ImageView after another URL should be loaded for the same ImageView, right @dnkoutso ? Therefore what I have said in my previous comment is wrong! While flinging http call will start but the http call will be canceled immediately when the ImageView will reused in the adapter (recycledView). Hence GC should not be the problem ...

Conclusion: I don't know what the problem is ...

I use it to load local files. It definitely doesn't seem like it cancels loading of items that you scroll by quickly.

Guys I am listening to the comments and will tackle this issue for 2.4.

We've talked about this with @JakeWharton on how to implement it. The truth is at the time of the library inception we did not do any tablet work and testing. For most cases scrolling and invoking requests is fine.

I am on vacation currently and will be able to tackle this next week.

PRs are still welcome of course.

Sounds good, Dimitris. Much appreciated :-)

@MizzleDK
I have added another improvement: I pause / resume the ThreadPoolExecutor while scrolling.
For my app i have noticed better performance. I'm curious if it will work in you app as well:
the jar: https://db.tt/3l01sQXJ
and like before, the PicassoScrollListener is needed on your ListView

Well... I'm not sure I see any difference.

I still have a ton of GC work being done. My LogCat output tells me that over the period of 1 second (23:34:37.380 - 23:34:38.380), the GC runs for 670 milliseconds - that's 67 percent of the time being used for garbage collection and that obviously means that the app stutters a lot.

Mind you that there's basically no GC work being done if I remove the Picasso calls. It has nothing to do with my layout or the amount of Views.

Latest master now adds scroll based loading. Try it out!

@dnkoutso can you please give me some guid link that how generate jar file from your picasso master. I never did that before and I am having difficulties. Thanks

@samia-pucit

  1. pull the latest code from master
  2. open your command line
  3. navigate to the picasso folder
  4. run this command: mvn clean install (maven must be installed on your machine)
  5. a folder target will be generated where you can find the jar file

@sockeqwe Followed your steps. I see this message in command line:

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 40.115 s
[INFO] Finished at: 2014-10-17T15:35:36+05:30
[INFO] Final Memory: 10M/95M
[INFO] ------------------------------------------------------------------------

But could not see target folder. Where will be its default location(windows)

With 2.4 you can now pause/resume requests and do scroll based loading.

I am closing this issue as it remains too vague to continue.

am having same problem posted initially.. i have a pager viewer and a listview in each tab .. i have multiple rows and in each row there is an image... switching fragments from pager is laggy because of picasso..
Picasso.with(context).load(link).into(Image);

Was this page helpful?
0 / 5 - 0 ratings

Related issues

julianonunes picture julianonunes  路  26Comments

nicolaslauquin picture nicolaslauquin  路  20Comments

pohh picture pohh  路  15Comments

justingarrick picture justingarrick  路  42Comments

kaciula picture kaciula  路  31Comments