Client using a lot of ram

9 replies [Last post]
Posts: 1003
CP: 7799

Let me first note this was not the case when the engine still ran on XNA.

Whenever you get to the map with Onett, the client takes up 400 mb of ram. I know this is a BIG map with chunks of 512x512 textures but it used to work fine a few months ago, back then it maybe took 100mb or so at most. Might wanna look into this.

Posts: 1647
CP: 26119

You sure it is related to the graphics? Since a 512x512 texture is only 1 MB (32 bits per pixel), so unless you have hundreds of these textures on the map...

Also, it might just be related to how the textures are being flushed. GrhDatas are assigned a ContentLevel when they are loaded which determines how frequently they are disposed. The decision is handled through a delegate, which the DemoGame implements by default as:

        static ContentLevel ContentLevelDecider(GrhData grhData)
        {
            const StringComparison comp = StringComparison.OrdinalIgnoreCase;
 
            var cat = grhData.Categorization.Category.ToString();
 
            // For stuff that will be put into a global atlas, use the temporary level
            if (cat.StartsWith("gui", comp))
                return ContentLevel.Temporary;
 
            // For stuff in the map category, use Map
            if (cat.StartsWith("map", comp))
                return ContentLevel.Map;
 
            // Everything else, return global
            return ContentLevel.Global;
        }

So you can try making that method always return ContentLevel.Temporary or ContentLevel.Map, which should flush out anything not needed by that map.

You can also try turning off the usage of texture atlases, too, or just better manage your atlases, which is done by default in the method:

        /// <summary>
        /// Loads the GrhInfo and places them in atlases based on their category
        /// </summary>
        void LoadGrhInfo()
        {
            GrhInfo.ContentLevelDecider = ContentLevelDecider;
 
            // Read the Grh info, using the MapContent for the ContentManager since all
            // but the map GrhDatas should end up in an atlas. For anything that does not
            // end up in an atlas, this will provide them a way to load still.
            GrhInfo.Load(ContentPaths.Build, _screenManager.Content);
 
            // Organize the GrhDatas for the atlases
            var gdChars = new List<ITextureAtlasable>();
            var gdGUI = new List<ITextureAtlasable>();
            foreach (var gd in GrhInfo.GrhDatas.SelectMany(x => x.Frames).Distinct())
            {
                var categoryStr = gd.Categorization.Category.ToString();
 
                if (categoryStr.StartsWith("character", StringComparison.OrdinalIgnoreCase))
                    gdChars.Add(gd);
                else if (categoryStr.StartsWith("gui", StringComparison.OrdinalIgnoreCase))
                    gdGUI.Add(gd);
            }
 
            // Build the atlases, leaving everything but map GrhDatas in an atlas
            var globalAtlasesList = new List<TextureAtlas>();
 
            if (gdChars.Count > 0)
                globalAtlasesList.Add(new TextureAtlas(gdChars));
 
            if (gdGUI.Count > 0)
                globalAtlasesList.Add(new TextureAtlas(gdGUI));
 
            _globalAtlases = globalAtlasesList.ToArray();
 
            // Unload all of the textures temporarily loaded into the MapContent
            // from the texture atlasing process
            _screenManager.Content.Unload();
        }

Posts: 226
CP: 0

Dw, he's being a fool and using the debug build. Debug build uses hundreds of mb of ram. Release build uses a couple of mb ^^

Posts: 1647
CP: 26119

Strange, wonder what part of the debug build is making it use so much then. Debug builds should only really be worse as far as instruction counts since it does an insane amount of checks everywhere. Don't remember there being too much extra stored in memory for debug builds.

Posts: 1003
CP: 7799

The amount of 512x512's on the maps is 120 by the way. And yeah, silly me, when I was thinking about it in bed the first thing that sprung(sprang?) to my mind was to try and see how much the release build uses.

EDIT:
Set Build mode to ReleaseTopDown, build all, run DemoGame.Client.exe ==> warps to Onett ==> 400mb ram usage. Sorry DF, not being silly.

Also:

- Map does not unload when logging out (mem usage still there)
- Music does not stop when logging out

Posts: 226
CP: 0

That's weird o_O The debug build for me uses 400mb, but release uses basically nothing :-/

Posts: 1003
CP: 7799

I had Dangoss test it on his computer and he also has a 400mb ram usage.

EDIT:

I'm guessing this is also the reason why the mapeditor eats memory >_>

EDIT2:

Tried the changing of the return value for ContentLevelDecider but no luck.

Posts: 226
CP: 0

Looks like I was being a fool earlier. The Release build also uses 400mb of ram, so I'm not sure why I thought it was low before? o_O

Setting ContentLevelDecider to always return ContentLevel.Temporary made no difference, neither did screwing with the atlases in LoadGrhInfo

Anyway, I found the mem usage dropped to 60mb, if I removed

            // Used GrhIndexes
            var usedGrhIndexes = reader.ReadMany(_usedIndiciesNodeName, ((r, key) => r.ReadGrhIndex(key)));
            BuildAtlas(usedGrhIndexes);

From DemoGame.Client.Map.LoadGrhs.

Which, I think stops the building of the TextureAtlases for all the grhs on the map?

So it seems to be the Atlases for that causing it (FYI, I think there's about 100 pngs being thrown at it)? Not sure what to do about this, or what the Atlases even do, so if you could help explain that, it might help Smile

Posts: 1647
CP: 26119

Then what is probably happening is just all your graphics used on the map are being forced into memory and staying there during the duration of the map since they are being stuck into the map's atlases.

I probably won't do anything about it since the average user isn't going to be using hundreds of huge images for each map... and most everyone should have no problem having all the graphics needed for a single map to remain in memory. Though maybe at some point I'll add better handling for detecting when the system is low on memory and clearing out unused textures.

Posts: 1003
CP: 7799

We're not going to make all maps like that ourselves, but the ones from Earthbound will be like that (cuz we're that lazy Wink)