- Home /
Unity iOS controlling heap size growth
I am currently developing a 2D sprite-based game (using SpriteManager) for Unity iOS using C#. On the iPhone, I am noticing horrible performance periodically (perhaps every 30-60 seconds). After some digging and using the internal iOS profiler, I noticed that my "used heap" size is reportedly increasing every time the profiler reports new data.
This used heap size grows until it approaches the "allocated heap" size, at which point one of two things happens:
1) The (I assume) OS allows the allocated heap to grow, allowing for the used heap to continue to grow. This only delays the inevitable garbage collection.
2) Most commonly, the garbage collector is called to cleanup memory, reducing the use heap size.
The issue I am having is that when the garbage collector is called, the "used heap" size properly reduces in size, but the time required for the garbage collector to complete its task is sometimes reported to take longer than 80ms. This, of course, is causing the game to freeze for several seconds while the garbage collector runs.
This is my first iOS app and I have a few questions regarding the heap:
1) Is it normal for the heap to steadily grow this way? If I am managing my memory correctly, shouldn't I be seeing the heap rise and fall, rather than steadily increase? I use a pooling system so that all my objects needed for a game level are instantiated at the beginning, so nothing is being Instiated() or Destroyed() as the game progresses.
2) Is it inevitable that the garbage collector will eventually need to free up memory, even with proper memory management? Will my used heap size eventually reach the allocated heap if I don't call the garbage collector manually?
SOLVED:
My particular issue had more to do with memory management rather than the garbage collector. For those having issues with large garbage collection times, I would encourage looking into the following:
For iOS, Use the internal profiler to track your used heap size and when the garbage collector calls. http://unity3d.com/support/documentation/Manual/iphone-InternalProfiler.html
A used heap that is rising quickly can be indicative of a memory leak. Although it may seem that the garbage collector is causing the issue due to large collection times, it may be due to the amount of used memory and the garbage collector having to analyze a large amount of memory to see what can be recovered. Manually calling the garbage collector is an option and may work for you, but always use profiling tools before and after manual calls to the GC to determine if it is beneficial.
Answer by cj_coimbra · Nov 08, 2011 at 05:04 PM
I believe I had this same problem when developing a 2D-only app for the iPad using Unity iOS.
I believe the heap growing is normal, however in my case, when the automatic garbage collect happened, it didn´t give back all the memory (I´ve read somewhere this is a known Mono issue). When the used heap reached the allocated heap, the last one increased. Also take a close look if you are using too much of "new Rect(...)" on your calls. They can contribute to fast "used heap" increase over time. I ended up having to manage garbage collection by myself or the allocated heap would keep increasing.
Other thing, look for image assets that have a high resolution and are set to GUI because these take a lot of memory. I found a 1024x1024 texture spending almost 8 MB of RAM, I set it to Texture and it went to 0.7MB
Also there is about 12 $$anonymous$$B of memory used by Unity, even if you deploy an empty scene with no game objects, assets or scripts.
Interesting. I was hoping I just had a leak somewhere and that the heap did not normally grow like this.
CJ, did you have any particular garbage collection strategy that worked for you? Even if I call the garbage collector rather quickly ( 'System.GC.Collect()' about every 30-60 frames ) it can still hit crazy collection times (over 60ms was pretty common!).
@cj.coimbra, actually there is no memory added to the heap by calling new Rect()
and that's an important distinction to make. Structs such as Rect are stack allocated. They are placed on the stack when they are created and removed from the stack when they are destroyed. So creating any structs such as Rects, Vector3's, Bounds, or Color won't add any new data to the heap.
@Peter G, I am not an expert but I can´t agree with you because I spent about three weeks over this issue (along with some others also related to optimization). I am aware of the distinction between struct and class but I still believe somehow "new Rect" in Unity will allocate memory otherwise the memory just allocate by itself for no reason at all for I didn´t use any "new" operator other than to create Rects for GUI stuff. Creating the Rects once and then updating only their boundaries made the used heap stop increasing so fast.
@$$anonymous$$eryu, I did garbage colletion based on time since last collection (every ~50 to 60 seconds) or upon a specific event to my app that was responsible for switching screens and other memory/cpu intensive operations. I think every 30-60 frames like you pointed is overkill. Also don´t limit yourself to the Unity profiler (the one that displays info on the debug screen) because that´s probably not all the memory in use by your app. Use that "Instruments" thing on $$anonymous$$ac to see how is the management memory going on. I was getting somewhere between 25 to 35 $$anonymous$$B on the Profiler and surprisingly 115 $$anonymous$$B(!!!) on the Instruments reading. You can see the low memory warnings and find out a target value for your app to use in peace with other apps or Springboard will kill your app at some point. Also, this does not mean you don´t have a leak somewhere.
@cj.coimbra, it might be a memory leak, but it should not allocate any new memory on the heap. If it is a leak, then you need to file a bug report because it should never behave like that. Structs are stack allocated so they won't add to your heap.