This post will give you some general advice on memory optimization for HTML5 games and some CocoonJS Canvas+ specific tips.
Effective asset loading
Preloading all the assets at the start is the easiest and quickest way to manage the memory but it only works for small games where all the assets fit into the available memory. You shouldn’t preload everything on a heavy game, only the assets that you need each time, and dispose of the unneeded assets as soon as possible. Your game memory usage depends highly on your game engine (some of them do a better job than others). Don’t expect that the browser or the garbage collector will fix all your problems and that you can stop worrying about effective memory management.
We recommend that you pack all your textures using one of the Sprite Packer tools out there. That way you’ll waste less memory and improve performance (by avoiding the number of context switchings) and loading times. Some HTML5 engines are able to pack all your textures at runtime, others don’t, so please check your engine features first.
The dispose method
CocoonJS’ Canvas+ environment exposes a method called “dispose” on canvas, image and audio objects. This method immediately frees the associated texture or internal buffer, which is very useful for games with heavy textures or for games that need a greater control over the memory.
Using this CocoonJS Canvas+ exclusive feature is very easy. Imagine we have an image object represented by the “myImage” variable.
The memory warning event
iOS and Android native applications are able to receive a memory warning notification from the system. The default implementation in Canvas+ and WebView+ environments is to perform a garbage collection and free as many internal cached data objects as possible.
From CocoonJS Canvas +2.1, the environment exposes the “memorywarning“ notification as a window listener. It is strongly recommended that you implement this method and free up as much memory as possible by disposing of cached data objects, images on canvases that can be recreated.
// dispose of cached images and canvases that can be recreated
Texture reducer is a CocoonJS Canvas+ exclusive feature. When your game targets all resolutions you need huge textures for iPad retina like devices and small textures for small mobile devices. A game developer has many ways to handle this:
- Create different asset packages, HD and normal. Good solution but bigger app size.
- Scale down HD resources. Excessive memory usage and performance impact on small devices.
The CocoonJS Canvas+ texture reducer feature can transparently do the job for you. It uses the third approach and it is highly customizable (for example, you can only apply it to certain resources). Check out the complete API documentation to see how to set it up.
As the texture reduction lowers the quality of the final images to be displayed, an interesting approach that we have recommended to some customers is to apply it only for certain device models, leaving higher resolution for some others (you can use the “navigator.userAgent” property to identify the device model). This, of course, it is not an easy task on Android due to the big number of device types, but on iOS is definitively an interesting option, specially for older devices such as the iPhone4 or the iPad Mini 1st generation.
Max Memory Threshold
This new CocoonJS Canvas+ exclusive feature available from version 2.1 and higher, exposes the “setMaxMemory” utility method. When the max memory threshold is set, CocoonJS checks the total amount of texture sizes (images and canvases). When the runtime memory size reaches the max memory threshold, CocoonJS disposes of the least recently used textures until the memory fits the threshold. It disposes of textures used for JS Image objects (which can be reloaded later if needed or are drawn again). It doesn’t dispose of canvas objects because they cannot be reconstructed if they are used again in a render operation. This extension is designed to be used in 2D contexts, because in WebGL contexts the developer is the one responsible for memory disposal.
Check out the API documentation.
Another CocoonJS Canvas+ exclusive feature available on version 2.1 and higher we have added the “cocoonLazyLoad” boolean property to Image objects (we have also added a duplicate called “idtkLoadDisposed” for retro compatibility with Construct2). When the property is set to true, the image is not loaded until it’s used in a render operation. Engines that load all the assets at startup can benefit from this property. But do not forget to purge the textures when they are not needed again, for example, using the dispose mechanism described earlier!
Canvas+ uses POT (Power Of Two) textures by default in 2d contexts. This is very useful for performance improvements, especially on mobiles with old GPUs. But it can waste memory on games that don’t use packed or 2^n textures. In CocoonJS Canvas+ version 2.1 you can allow NPOT textures in Canvas2D contexts (they were already supported in WebGL).
Check out the API documentation.
We have covered some basics of memory management in HTML5 games and exposed Canvas+ specific tips and tools. We are always open to your suggestions. Remember that if you have some problem with memory usage in Canvas+ and you think that the problem is on our side you can send us a testcase and we’ll be glad to help you.
Additional Notes about Ludei’s Canvas+ Environment