Images loader and memory footprint. iOS

Sergey Petrachkov
3 min readDec 3, 2021

--

Disclaimer: This article is not a guideline or any kind of tutorial. Just a bunch of observations and experiments.

Even though modern devices are pretty powerful in terms of RAM and other units, sometimes we still need to think about resources utilization. I’m gonna tell you a story of how I worked on some huge refactoring and had to update the images loading service.

We operate lots of images and need to make sure that the memory footprint is optimal and we’re not utilizing too much RAM. The code that I’m gonna share here is a simplified version.

So, we need to download a lot of images and process them. When I say “a lot”, I really mean it. We need to download and process thousands of images for some of our users. That’s why we need to be careful so we don’t exceed the limits.

In the general case we can load images like this (Yes, for better results we can use downloadTask, but this time we’ll be using dataTask):

Let’s use this method and load like 670 images:

Simple for-loop inside a queue, right? Let’s see the results:

We see that the highest memory consumption was around 134 Mb for 674 images. Not great. Let’s try and improve that.

If we add autoreleasepool we can improve these figures drastically.

So, we wrap image loading into autoreleasepool and get the following results:

The highest memory consumption is around 23.8 Mb. Amazing, isn’t it?

But what if we want to bring in some modern code? Let’s try Combine maybe?

Here we have 2 methods: one to load a single image, another one is to load an array of images sequentially. We get these results:

The highest memory consumption is 23.2 Mb. It’s a little bit less than with the old-school loading, though I am not sure why. But the good news is that Combine seems to be efficiently utilizing the memory and you don’t need to bother about autoreleasepool and memory management (not about memory leaks though! But it’s another topic, there are lots of articles out there about possible retain cycles).

Alright, let’s move on and try the latest Swift concurrency. Async await is now only available on iOS 15 and higher, though we the developers are looking forward to Xcode 13.2 release with swift concurrency backward compatibility.

How much easier it looks! Right? What are the metrics, though?

22.5 Mb, wow! It’s even less than Combine. Now I really want Xcode 13.2 to be out sooner.

So, today we learned that sometimes we can improve our memory footprint by doing very little.

You can check out the full project here: https://github.com/SergeyPetrachkov/SequentialImageLoaderSandbox

--

--

Sergey Petrachkov

Amsterdam-based iOS developer born and bred in Siberia. Follow my "Metal in the Attic" Youtube channel :)