8

I'm sorry in advance as maybe this is a dumb and noob question...

I'm using SDWebImage to display pictures in a UITableView in my cellForRowAtIndexPath method, using the classic

[cell.pointPicture setImageWithURL:[NSURL URLWithString:thePoint.imageURL] placeholderImage:[UIImage imageNamed:POINT_DEFAULT_IMAGE]];

(the displayed pictures are light and well compressed jpgs, just some ko, and yes I'm using dequeueReusableCellWithIdentifier of course).

When I inspect my app with "Instrument - Allocations", and just scroll down my UITableView (with 40 cells containing picture, a bit like Instagram), I got a huge amount of memory used ! (see screenshot)

instrument allocation screenshot

But it seems to be "VM", and especially "VM: CG raster data" from the coreGraphics library.

So the questions are :

  • Is it normal?
  • Is that a serious problem?
  • Is there a way to avoid this?

I'm sorry but after few search on the web I can't find any relevant information concerning the "VM: CG raster data"... Any idea? Thanks in advance !

  • It's all the rasterized versions of your views used for actual display on the screen by the render server. You can expect large memory load, especially if you've got large images that you're scaling down in the views. Run the leaks instrument and see if you get any actual leaks. – Jason Coco Oct 27 '13 at 16:18
  • thank you @JasonCoco for these explanations. Yes the picture size is bigger than the view which display it. For the leaks, Instrument is not showing any... – Fabien ParseError Oct 27 '13 at 16:33
  • @JasonCoco I just tried to display pictures of the exact size of the view (640x640, then 320x320) to avoid all scaling down. Unfortunately the amount of CG rester data used stay the same... What also consider strange is that the amount of memory used is never released... I also can't find any memory leak. – Fabien ParseError Oct 28 '13 at 17:24

4 Answers4

4

I experienced the same issue and found the root cause, at least in my implementation.

Root Cause

The root cause was that my table cell stored a strong pointer to the image which is stored in SDWebImage cache. This strong pointer, caused the memory release function of SDWebImage removeAllObjects not to release any memory when receiving a memory warning from iOS.

Solution 1 - Keep weak pointers from within your ViewController and allow only SDWebImage to keep a strong pointer to all UIImage objects.

Solution 2 - Implement - (void)prepareForReuse and set the image pointers to nil

To test this solution run your application and simulate a memory warning - You will be able to see the data removed

avihayas
  • 281
  • 2
  • 10
  • Can you please provide code snippet for Solution 2? – Raptor Jun 09 '14 at 07:41
  • According to Apple and my tests `prepareForReuse` is called right before being reused, thus right before the pointers are set to a new image so setting it to `nil` right before that won't make a difference. It would if they could be set to `nil` when the cell is enqueued but there doesn't seem to be a method for that. – Rivera Jun 30 '14 at 01:41
  • @avihaya Hi, bro. could you edit the answer by play more code in on it? – aircraft Nov 30 '16 at 07:20
0

As explained to me by someone working on SDWebImage :

SDWebImage cache images is using NSCache. It is discardable memory. See Apple documentation, so this is a perfectly normal behavior and the memory is released if needed.

Raptor
  • 53,206
  • 45
  • 230
  • 366
  • 1
    Though it is true that memory is released if needed, you can get a vastly better performance by doing two things 1)Resize the image upon download to fit your needs 2)modify the caching logic in SDWebImage to store the resized image in cache. I did this and my memory footprint went down from 200MB to about 40MB max now. I have a uicollectionview in a grid with 2000 images - all being downloaded from a server. – Anil Puttabuddhi Nov 11 '13 at 15:31
  • @AnilPuttabuddhi could you post your code there to show more detail? – aircraft Nov 30 '16 at 07:23
0

I had the same issue. My problem seemed to originate from something else than the SDWebImage cache but since it did contribute to the memory buildup, the first thing I though was that the cache could be the cause of my problem. But it wasn't. It could be you have the same kind of issue. Keep in mind that I am using ARC.

  • Run the profiler with the Leaks template and check for the allocation of your own classes in the Allocation Summary.
  • Dive into them and check how they are allocated, if there are leaks. Mind that a leak doesn't show up in the Leaks instrument because you are using ARC. So Instruments could think everything is going oké but there still could be a leak somewhere. By diving in to the allocation of your own classes you could figure out what is going wrong.
  • Keep in mind that the retain/release count information is only provided when using the Leaks template and not while using the Allocations template.

My problem was that I was referencing instance variables and self directly from within blocks without reassigning them to __weak variables. When self is used within a block it will automatically be retained by ARC and sometimes never released. A weak reference prevents that from happening.

For example, this is wrong:

[[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardDidShowNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
    [self.view setContentOffset:CGPointMake(0.0, kKeyboardOffset) animated:YES];
}];

You should call self using a __weak reference like this:

__weak YourViewControllerClass *weakSelf = self;
[[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardDidShowNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
    [weakSelf.view setContentOffset:CGPointMake(0.0, kKeyboardOffset) animated:YES];
}];

Since my app uses a lot of block's I had a ton of leaks the Leaks instrument could not detect. When I fixed them the memory problem was gone.

I hope this helps.

thijsai
  • 1,795
  • 1
  • 18
  • 26
0

Although NSCache will free memory on low memory system notifications also more critical (and way smaller in memory footprint) objects will get discarded in other parts of the program.

It would be better to set the library's maxMemoryCost (which sets the NSCache totalCostLimit) to a limit to prevent SDWebImage from triggering memory notifications.

Rivera
  • 10,792
  • 3
  • 58
  • 102