Memory Management Advice

rated by 0 users
This post has 3 Replies | 2 Followers

Top 100 Contributor
Posts 42
SunBurn_Community_Licensee
Duckocide Posted: 10-22-2011 4:25 AM

I'm after any advice / pointers on memory management, unloading, disposal, etc with Sunburn

I'm running in to cumulative memory issues with Copernicus One (http://youtu.be/7PWPM-dv6a8). With all the models, textures, sound effects and all, the consumption of memory is considerable. No problem I thought, I'll develop a caching mechanism where items not needed in subsequent locations won't be cached. In order to have good control, every location object (prop in the adventure sometimes made up of more than 1 model) has it's own ContentManager. I can load, unload (and dispose) at leisure. with disposal code along the lines... 

 

       /// <summary>

        /// Clears out model entries that are not cacheable (unloads content)

        /// </summary>

        private void RemoveUnCacheableModelEntries()

        {

            removals.Clear();

            foreach (ModelEntry mentry in ModelCache.Values)

            {

                if (!mentry.Cacheable)

                {

                    removals.Add(mentry.ContentReference);

                    // Lose all content...

                    foreach (ModelMesh mm in mentry.Model.Meshes)

                    {

                        foreach (ModelMeshPart mmp in mm.MeshParts)

                        {

                            mmp.IndexBuffer.Dispose();

                            mmp.VertexBuffer.Dispose();

                            mmp.Effect.Dispose();

                        }

                        foreach (Effect e in mm.Effects) e.Dispose();

                    }

                    mentry.AssociatedContentManager.Unload();

                    mentry.AssociatedContentManager.Dispose();

                }

            }

            foreach (string key in removals)

            {

                ModelCache.Remove(key);

            }

        }

 

3D and 2D Sounds also are Dispose()'ed after use. I've even gone on a 2D Texture rampage looking to ensure any other content I load is not to blame (i.e. Only reloading if IsDisposed, making certain references static, that sort of thing).  

Here's the thing. Even when I don't cache anything, I end up with an amount of "residual" memory consumed. I've been testing this with a triggered reload of the same location (as if you are repeatedly going to the same location). In theory, the resultant amount of memory consumed post load should be more or less the same. Oh no... I have a huge delta (25MB).

OK I thought, it can't be the models, I'm disposing of eveything, it must be something else. Let's go for the nuclear option and try and knock down everything that is probably generating large managed / unmanaged lumps of data (Textures, Vertex buffers etc). So, In between locations I'm doing this...

 

        private void ClearDownSunburn()

        {

            SunburnContent.Unload();    // Sunburn (Scene's) content manager (not to be confused with location objects, lights mostly)!

            SceneInterface.Clear();

            List<IManagerService> imss = new List<IManagerService>();

            SceneInterface.GetManagers(imss);

            foreach (IManagerService ims in imss) { ims.Clear(); ims.Unload(); }

            SceneInterface.Unload();

            frameBuffers.Unload();

        }

I do use other libraries such as BEPU and have chosen to knock that down in between locations. This isn't a heft data user (It's all Math).  

Now, the interesting thing is, I get a large (understandable) memory delta (+26MB) when the following lines of code first execute (in Draw) post location load and set-up. It did make me wonder if (despite the SunburnClearDown() ), some unmanaged garbage is hanging around (and explains the accumulation I've got) - I do invoke GC.Collect() between locations (I've even got one triggering every minute at the moment in desperation).

                // Render the scene.

                SceneState.BeginFrameRendering(View, Projection, gameTime, SceneEnvironment, frameBuffers, true);

                SceneInterface.BeginFrameRendering(SceneState);

                 :

                 Rendering.... 

                 :

 

Any thoughts... ?          

 

Top 10 Contributor
Posts 5,368
Employee
SunBurn_Studio_Licensee

Hi Duckocide,

To fully dispose all loaded assets you only need to do the following:

  • Clear the SunBurn SceneInterface (this automatically cascades to all contained managers)
  • Unload all xna ContentManagers


If you'd also like to free up graphics resources used by SunBurn (which are recreated as needed when rendering subsequent frames):

  • Unload the SunBurn SceneInterface (this automatically cascades to all contained managers)
  • Unload the SunBurn LightingSystemManager


Please note the above does not free any graphics resources created by the game.  For instance if you create custom vertex buffers, index buffer, effects, or clone effects, these all need to be properly disposed when unused.

But here again SunBurn makes this relatively easy for you, just assign these resources to SunBurn when created to have the engine dispose them for you during SceneInterface.Unload():


BasicEffect gameeffect = new BasicEffect();
// assign to SunBurn so the engine cleans up the effect during Unload()...
sceneInterface.ResourceManager.AssignOwnership(gameeffect);


Let me know if this helps!

Follow me on Twitter – development and personal tweets
Awesome XNA Videos – Lighting, Rendering, and game videos

Top 100 Contributor
Posts 42
SunBurn_Community_Licensee

Ahh... 

sceneInterface.ResourceManager.AssignOwnership(gameeffect); 

Could be just what I'm looking for! Will certainly help on the predictability front. As you can probably guess from the game, a number of Deferred effects are being created and disposed in Copernicus One. I'll give it a go and post back :)

Thanks John!

Top 100 Contributor
Posts 42
SunBurn_Community_Licensee

Well. I think that has done the trick. I need to debug down through some other drawable components, but on the face of it, the advice has certainly helped. Brilliant ... Thank you :)

Page 1 of 1 (4 items) | RSS