Bloated memory use after import from C2 to C3

  • Hey everyone,

    I'm converting a C2 project to C3 and I've solved most of the little bugs it created. However I've noticed the (estimated) image memory used you can see in the NW.js debugger has inflated by 50% in the process. I noticed the Runtime used also impacts this value.

    Here is the debugger from C2 : 194.4mb

    Here is the debugger from C3 (with C2 runtime) : 243.9mb

    Finally here is the debugger from C3 (with C3 runtime) : 313.4mb

    Is it a known issue or should I a file a bug report ?

    Mobile is not a primary target platform but I plan to release the game there in the future, so memory issues can be a big deal.

    I've found this report that's kinda similar but the problem was apparently spritesheets being sometimes bigger than 2048*2048 and there's no object in my project that's even close to being 2048 pixels wide.

    github.com/Scirra/Construct-3-bugs/issues/2094

    Thanks in advance for your opinions :)

  • Construct 3 uses a different spritesheeting algorithm. It can result in better performance but in some cases uses a bit more memory. You can customise it by changing the max spritesheet size setting in advanced project properties.

  • Try Construct 3

    Develop games in your browser. Powerful, performant & highly capable.

    Try Now Construct 3 users don't see these ads
  • Thank you Ashley. If you don't think it is alarming then I won't dig too much into it. I'll test my game again on older configurations and see if the performance/memory tradeoff is problematic or not :)

  • Investigating a little more I think I bumped into the problem, and to me it seems reaaaaaally severe.

    Here is a test case for both C2 and C3 :

    https://www.mediafire.com/file/b3ij98kz87g6luq/ConstructMemoryProblemCase.7z/file

    In each of the projects, I have 8 sprites of the size 800px*800px.

    In C2

    If you create these sprites on an empty layer one by one, the memory progressively increases. From base 6.6mb to 9mb to 11.5mb etc... That's around 2.5mb per sprite added.

    If you restart the layout, the memory is purged and you go back down to 6.6mn.

    In C3

    • C3 groups the sprites into spritesheets of 2048*2048, and these can hold 4 sprites of 800px*800px at a time. Clicking Tools >> View Spritesheets you can see Sprites 1 to 4 are together and 5 to 8 are together.
    • if you create sprite1 on an empty layer the memory increases by a massive amount, from 2mb to 18mb right away!
    • try to create sprite2 and... the memory doesn't budge.
    • try to create sprite5 (which is on the second spritesheet) and the memory jumps again to 34mb.

    ==> conclusion : C3 loads the ENTIRE spritesheet containing a needed sprite, even if the other sprites inside are not needed. That's a massive waste of memory if you ask me!

    Even trying to unload unused memory manually won't change this memory load.

    It is a very big problem and I really don't think it's intentional.

    • Another problem : If you restart the layout... the memory stays the same even though the sprites are not here anymore ! You have to manually purge the memory using the system action "Unload Unused Images from Memory".

    ==> memory is not automatically purged on start of layout!

    This to me seems like another very big problem that didn't exist in C2.

    I hope I'm doing something wrong because these would be fundamental problems for the image memory management system, wouldn't they? I reproduced the case easily with a basic project, so that convinced me the problems I first encountered weren't related to the fact I was trying to convert a pretty big project from C2 to C3.

    Thanks in advance for your opinions on the matter. If I need to write a bug ticket, I can, just tell me.

  • Spritesheeting is a fundamental tradeoff between low memory use but poor performance (every single image is separate), and high memory use but excellent performance (all content on a single huge spritesheet which is always in memory).

    C2 has a major limitation in its spritesheeting engine: it cannot combine different objects on to one spritesheet. This puts it a long way towards the low memory but poor performance end of the scale.

    C3 improved the spritesheeting engine so it can combine multiple types of objects on to the same spritesheet. It also analyses the layouts in your project, identifies the types of objects that tend to be used together on layouts, and uses that grouping for spritesheets. This is aimed at making sure when a spritesheet is loaded in to memory, there is minimal waste from having to load objects from different layouts that aren't currently in use. This is IMO a better compromise and is closer to the middle of the performance/memory scale.

    However in some cases, particularly if you have not paid any attention to the way Construct's layout-by-layout memory management works, the memory usage can increase. For this reason we added a property to help control it. Further, given most devices have loads of memory these days - 1 GB can probably be considered low-end, and any image memory use under 500mb is probably no issue at all - it seems appropriate to optimise a bit further towards the high performance end of the scale.

    The main downside is people think this is some kind of fault, as in this thread. It's not, it's an intentional part of C3's design.

  • Thank you again Ashley for your quick answers :)

    1) Spritesheeting

    Ok so this spritesheeting is normal behavior... I don't question its general usefulness, but it feels kinda counterproductive in certain instances, especially when it groups objects that are never meant to appear together. Sometimes the algorithm doesn't have a choice to do so I understand, but still.

    For example in my project I used to have a sprite with 100 frames of 800x800 (reprensenting a whopping 300mb by itself), but since there would always only be one that'd be used per layout I splitted it in a hundred sprites 800x800 instead.

    With the spritesheeting this optimization is diminished since the game needs to load at least a spritesheet each time, which represents 4 sprites (3 being useless).

    It's probably not feasible, but since we can consult the Spritesheets it would be great to be allowed to isolate one or more sprites, effectively saying : "these must not be grouped with other sprites". That would save a lot of image memory and enable anyone to build their own Performance/Memory Scale sort of.

    Maybe it's not that big a deal on desktop, although it probably depends on the project, but I suppose for mobile it wouldn't be negligible?

    2) No purge at new layout

    I read and re-read the layout-by-layout memory management page, and the simple test I produced directly contradicts it. Supposedly :

    When the layout ends, all images that are loaded but not used on the next layout are released from memory.

    If an object is not placed in the layout view, but events create it at runtime, its images are not pre-loaded.

    In the example I linked, after you've created sprites through events that bump the memory usage from 2mb to 34mb, restarting the layout should purge the memory back to 2mb since they are not on the next layout. And it's not the case, it stays at 34mb and memory must be purged manually :x

  • Did you even try to decrease the size of the spritesheet like ashley explained?

  • I did, but the memory won't decrease back so much, plus that means giving up on the performance improvements Ashley said were linked to bigger spritesheets :x

    But if this lack of flexibility is voluntary I'll be moving on and I won't bother you with more questions.

    What about the absence of automatic purge at layout restart though ? I can't help but think it contradicts the manual.

  • Construct 3 makes the assumption that if you created objects on a layout and then restart it, you'll probably use those objects again, so it keeps them in memory. That's all.

  • Ok, thank you! I've just got to keep this in mind then :)

Jump to:
Active Users
There are 1 visitors browsing this topic (0 users and 1 guests)