UIImage memory

Does reloading new images into a UIImage view increase the memory usage each time a new image is loaded, thus potentially leading to a memory leak? If so, then do I need to release the memory used for the currently loaded image before reloading the UIImage with a new image?

Replies

Setting the UIButton image to NIL and UIImage image to NIL before I reload it does not seem to resolve my memory issues. It may reduce the memory a bit, but I am not sure how to tell for certain.


mute_Button.setImage(nil, for: .normal)  
mute_Button.setImage(UIImage(named: muteOffImageFile), for: .normal)



imageObj.image = UIImage(contentsOfFile: "")  
imageObj.image = UIImage(named: imageFile)

I understand using "UIImage(named: ***)" to load an image onto a UIButton or UIImage will result in the image file being cached automatically. Since the total size of all 52 card images combined together have a small total size of 1/2MB only then I am assuming this automatic caching of images is not what is causing the didReceiveMemoryWarning( ) one of the players received while playing the game.


I was trying to determine whether anything in my application was wasting memory but really do not know how to go about figuring this out. I was thinking it might be due to loading images into UIButton and UIImage views, but know I do not know what to think.


Question:

If I have 6 UIImage views on my storyboard and eventually load 52 different card images onto each individual UIImage while playing many rounds of my game, then does each UIImage view cache 52 separate images individually (ie: 52 images x 6 UIImage views = 312 cached images) OR does the system only cache the total 52 card images only?

The documentation of UIImage just says that init(named:) uses cache, but it says nothing about its details.

So, just my guess, it is very likely that the name passed to init(named:) is used as a key for caching, so, if you have only 52 names, UIImage would cache 52 something in memory.

Though, a cached image in memory may be far bigger than the image file.


Another guess, only 52 card image would rarely cause memory issue and you may have something wrong in other parts of your code.

Have you checked memory leaks using Leak?


One more, as far as I tested, setting nil does not affect internal memory usage of iOS.

I will look into what Leak is ... thanks

You may have found it already, but you can find many articles searching with "xcode how to use leaks".

("Leaks" is the right name and it is included in the Instruments of Xcode.)


Anyway, pleae tell me anything you find that may be related to your issue.

This dictionary structure of cache would explain the need to nil the UIImageView as well, to flush the cache, and not individual images, that clear only one in 52.


That's what was hinted in initial link:

set the UIImage AND the UIImageView to nil (not sure if both are needed), and sure enough, it released the memory.

https://stackoverflow.com/questions/17666679/uiimageview-not-releasing-memory-according-to-vm-tracker-low-memory-warnings

Sorry, but I do not understand what you mean by this. Any parts of this thread, as well as the content of the link, do not refer dictionary structure.

And even if we assume some sort of dictionary structure, it does not explain anything. A simple dictionary-based cache holds strong reference to the entries. Something like UIImageView can have a strong reference to the image held in the cache, but two references are dependent and releasing one would not cause another to be released.


If you know some sort of cache implementation which flushes one entry if a reference to the entry somewhere else is released, would you please show me a sample implementation?


That's what was hinted in initial link:

Sorrry, but the accepted answer was written about 7 years ago. Have you confirmed that the same thing applies to the latest iOS and the latest Xcode?


And one more, the answer is suggesting that setting its image to "nil" before popping the controller, not before setting another image to the image view.


As I wrote, the details of caching feature is not documented well, something you have suggested in this thread might have effect. Could you please show some concrete example that your setting-nil do have effect. I would like to see a testable code.

No, I've no code to test, I was just trying to elaborate from your statement:

the name passed to init(named:) is used as a key for caching,


I may have been wrong in inferring that this key was for a dictionary (or something like) ; but the point was that remiving the 'data' for this key would not clear the complete cache with all keys.


Was I badly misanalyzing how all this could work ?

Was I badly misanalyzing how all this could work ?

Some parts of your logic may be wrong, and some assumptions or tests of mine may not be represeting the actual issue.


Maybe we need to wait for the fact which will lead us to solve the issue. I expect that OP finds something soon.


You're right, it was a bit risky from me to elaborate too much on assumptions. Facts based conclusion is just better (in code or in many other cases).

The reason I created this post was due to the fact that one of the players who I was playing against was kicked out of my game application due to didReceiveMemoryWarning() being called. I have never seen this memory warning occur while testing for the past many months. I assumed I might have some memory leaks since I never checked before or possibly be using too much memory in my application. I read somewhere that setting UIImages to nil might free up memory so I thought I would look whether this was true, so decided to start this post.


That being said, I just recently performed the following and concluded I do not have any memory leaks in my application:


I ran the "leaks" instrument while running my application on my real iPhone device (ie: leaks does not work on the iOS simulator running 13.4). The leaks tool never reported any leaks in my application code. There are however various leaks occurring (64bytes, 128bytes, 256bytes in other code which I do not change). I am ignoring those areas.


I ran "Malloc Stack (Live Allocations Only)" and did not see any purple exclamation points in the Debug Navigator ever


In the "Debug navigator" I clicked on "Memory" and saw my application runs at a constant 49-51MB from start to finish whether 2,3 or 4 players are in the game. If I was leaking memory I assume this memory usage amount would steadily increase throughout the 20-30 minute gameplay to some value much much higher

So may be your friend player ran out of memory because of another app.


You should ask him/her if there was a lot of other apps running, or a very hungry one.

My friend did indicate she had a lot of other applications opened and has only 2Gb left of overall available space on the iPhone. I guess this might explain the memory issue.

I am ignoring those areas.

I do not understand why you can so easily ignore them.

Even if they point to some other place than your code, the leaks did happen while your app was running.

Unless it is clarified those leaks are caused by some iOS bugs and cannot avoid, you may need to fix those leaks.

Users tend to keep apps running for a long time, small leaks would sum up to a big amount while running.


If I was leaking memory I assume this memory usage amount would steadily increase throughout the 20-30 minute gameplay to some value much much higher

Do you expect users to shut down your app after each half-hour gameplay? As I wrote above, users may keep many apps running (like your friend), so even a slow rate increase should not be ignored, when it grows constantly.


Generally, didReceiveMemoryWarning() being called does not mean that your app has non-ignorable memory leak. If a user keep many apps up and running, and total amount of memory usage gets higher than some system limit, iOS would send didReceiveMemoryWarning to any apps running, some unfortunate apps would be terminated after (or before) that.


But please keep in mind, your app needs to properly respond to didReceiveMemoryWarning, you may need to free as much memory as you can, for example, some cached content which is not immediately in use should be released.

As you have no control on the cache used by UIImage(named:), using UIImage(contentsOfFile:) might be a good option to accomplish that.


---

So, in my opinion, your usage of UIImageView or UIImage is not a direct cause of didReceiveMemoryWarning() being called, and setting nil before replacing UIImage does not help anything. But you should better re-consider fixing the leaks as much as you can and responding to didReceiveMemoryWarning properly.

My application does not cache any specific game data, files or URL images so I do not know of any cached files or memory which I could free when a didReceiveMemoryWarning( ) was received.


The memory leaks, which were reported by the "leaks" instrument, are not pointing to any functions that I created in my code so I have no idea how to progress those. The memory leaks are related to functions which make no sense to me. Knowing I just taught myself swift coding and just created my first application only, I do not currently posess the knowledge to know how to progress issues in code which I did not even write.