The hidden cost of String allocation in Swift

Shivam Jaiswal
Mac O’Clock
Published in
3 min readMay 3, 2020

Swift automatically allocates and deallocates memory on your behalf. Some of that memory it allocates on the stack and some on the heap.

As we all know, any data type which is of Value Type gets stored on stack memory and Reference Type gets stored on managed heap memory.

Right? The answer is NO! Not always. Actually it all depends upon internal implementation on the data type.

And it may come as surprise to you that despite being a value type, String actually stores the content of its character indirectly on the heap. And storing data on heap is much heavier operation as compared to stack.

Hence, you should use String wisely instead of randomly allocating it just for the sake of your convenience.

Let’s understand it by an example from a messaging application I’ve been working on. I am trying to make a bubble image, which encapsulates the chat message text.

My makeBalloon function is what generates this image and it supports a configuration of different or the whole configuration space of different balloons.

Now, the makeBalloon function needs to be really fast because I call it frequently during allocation launch and during user scrolling. And so I have added this caching layer. So, for any given configuration, I never have to generate this balloon image more than once. If I have done it once, I can just get it out the cache. The way I have done this is by serialising my color, orientation and tail into a key, which is a String.

Now there is a couple of things not to like here. String isn’t particularly a strong type for this key. I am using it to represent this configuration space, but I could just as easily put the name of my dog in that key. So, not a lot of safety there. Also, String can represent so many things because it actually stores the content of its character indirectly on the heap. So that means every time we are calling into this makeBalloon function, even if we have a cache hit, we are incurring a heap allocation.

Hmm, let's see if can do better by reducing the cost of allocation.

Well in Swift we can represent this configuration space of color, orientation and tail just by using a Struct. This is a much safer way to represent this configuration than a String. And because Structs are first-class types in Swift, they can be used as the key in our dictionary.

Now when we call the function, if we have a cache hit, there is no allocation overhead because construing a struct doesn't require any heap allocation. It can be allocated on the stack.

The Time Difference

Let’s see the time taken by String and Struct when each of them is allocated a million times.

And the time consumed by Struct is more than 100 times faster than String allocation.

Where to go from here?

For more details visit WWDC’16’s Understanding Swift Performance.

--

--

Shivam Jaiswal
Mac O’Clock

Just another developer, trying to make a diffrence.