Search Unity

Heap memory difference

Discussion in 'Editor & General Support' started by PopovPingle, Sep 6, 2019.

  1. PopovPingle

    PopovPingle

    Joined:
    May 2, 2019
    Posts:
    16
    Hello,
    I have problems with my heap.
    While i am plaing in same places my heap has different size. Like when i starting game from save my heap is 730mb used but after loading this save 2-3 times i got 1040mb in heap.
    First i thought that i cache somthing and etc, but as far as i reserching this issue i made 2 memory captures with Unity Memory Profiler 2.0.
    There is big visual differens about managed objects, but when i try analyze this by script its says that size of managed obects is about 550mb and difference between two snapshots is 20mb. I dont think that problem is in my script couse it is pretty simple.

    Please make me clear with where can i find lost megabytes.

    There is link to captures
    https://drive.google.com/drive/folders/1krAPpH1A0_KVLBpdxNgKTsPxVGHZ55EY?usp=sharing
     
  2. MartinTilo

    MartinTilo

    Unity Technologies

    Joined:
    Aug 16, 2017
    Posts:
    263
    Do you mean the new Packaged Memory Profiler? With that tool, you might want to use the Diffing capability and take a look at the memory map. It could be a scripting heap fragmentation issue you're facing, or it could be other Mono allocations that are not tied to objects, which is why you wouldn't see this issue when you just compare the objects
     
  3. PopovPingle

    PopovPingle

    Joined:
    May 2, 2019
    Posts:
    16
    Yeah i mean Packaged Memory Profiler. So what can i do with scripting heap fragmentation or with Mono allocations that are not tied to objects?
     
  4. MartinTilo

    MartinTilo

    Unity Technologies

    Joined:
    Aug 16, 2017
    Posts:
    263
    This guide is a bit older but a lot of it still holds true. This manual page is newer but doesn't touch on fragmentation.
    Disclaimer: With all of the tips in these, validate by testing and profiling that the optimizations actually yield the result you're expecting.

    So if you have that picture of the fragmented heap of the guide I first linked to in mind: As you allocate or load stuff into memory, try to order your loading procedures by how long you intend to keep that memory around. So everything that is always going to be around loaded first. Stuff that stays around for shorter duration, like a scene, is then loaded on top. Short term memory allocated last. Avoid high frequency allocations because of the performance overhead for allocating that. Check the Profiler for GC.Alloc occurrences during game play. If you can avoid these allocations, do so, otherwise see if you can pre-allocate and reuse the memory. If none of that works, reduce it as much as possible to avoid GC.Collect spikes (or use the Incremental GC if you're not CPU bound).

    Next step in your memory strategy is to then free that memory, ideally in reveres order, from short term to long term, but in any case to make sure you've freed the memory before you load in new stuff, e.g. for the next level or a new save game load. Use the memory profiler to check if you forgot to free some memory up and check why it is still around. Basically, you want to make sure that the memory areas for your higher frequency memory are as clean as they can be, so that any newly loaded memory doesn't have to find space between previously allocated memory but just write back into the freed memory regions again, avoiding the creation of holes in there, i.e. memory fragmentation.

    In other words, think of the memory as stacked layers and plan around how you'll add or remove them as you go from one game state to the next.

    Also, I know that this might sound like too much and overwhelming so keep in mind, that you don't need to do this perfectly to start seeing benefits from following such a strategy. You'll also likely not have to go all the way with this, just implement the broad strokes first and then go into more details then as far as necessary to be able to ship a performant game that doesn't run out of memory in a reasonable time frame.

    That said, if you are CPU bound and see GC.Collect spikes or if even the Incremental GC hurts your performance to much, you might want to spend some extra focus on getting your GC.Alloc during game play as far to 0 as possible regardless.


    Regarding non object bound Mono allocations: These consist mostly of Scripting Meta-Data, for your managed types. Pretty much the only reasonable thing you can do to reduce that is to avoid the use of any kind of Reflection in your code, which will cause this metadata to be allocated.
     
    ibbybn likes this.
  5. PopovPingle

    PopovPingle

    Joined:
    May 2, 2019
    Posts:
    16
    Oh i have a lot of Reflection,
    as i understand u said that it can make memory issues? how much can i lost in memory if i use crazy amount of Reflection?
     
  6. MartinTilo

    MartinTilo

    Unity Technologies

    Joined:
    Aug 16, 2017
    Posts:
    263
    There is no direct way to see that clearly right now, safe for taking out all use of Reflection an compare with the state before.
    You can try to take a snapshot via MemoryProfiler.TakeSnapshot while or shortly after you've made use of Reflection but before the Reflection objects you allocated that way have been collected by GC. Then you can search the Managed Objects view for "Reflection." in the Types column. Once they are collected, they just fragment your heap so you can only see them as "white space" (technically blue I guess ;) ) in memory map, when you look at Managed Memory sections that don't contain Managed Objects.
     
  7. PopovPingle

    PopovPingle

    Joined:
    May 2, 2019
    Posts:
    16
    Your memory profiler doesnt help, we have hundreds of millions objects and we have heap size of 1gb, and it makes profiler function "diff" broken and there are nothing to help broken so i cant use it.
     
  8. MartinTilo

    MartinTilo

    Unity Technologies

    Joined:
    Aug 16, 2017
    Posts:
    263
    In which way does it break and could you please file a bug report so that we can fix it?