Search Unity

Heap memory snapshot creater / dumper

Discussion in 'Assets and Asset Store' started by Zuntatos, Dec 14, 2016.

  1. Zuntatos

    Zuntatos

    Joined:
    Nov 18, 2012
    Posts:
    612
    Developing my game, I ran into an issue with a memory leak due to a static field somewhere accumulating references to objects that should be dead. None of the existing tools to find out what was happening where did what I wanted them to do, so I made my own and uploaded it to github for future use by others.

    Link: https://github.com/Zuntatos/UnityHeapDump

    Copy of the readme commences:

    UnityHeapDump
    Tool to dump memory to text files for inspection

    Primary use is to find which static fields hold how much memory in order to find possible object leaks. For leaking of unity objects, please use the detailed memory profiler included in Unity3D. Total tracked memory found by this script can be much higher than the heap size, as an object with shared ownership will be counted towards every owner.

    Use the menu item "Tools/Memory/Dump Heap" or call UnityHeapDump.Create() somewhere from your code to create a memory dump at %projectroot%/dump/. The process may take several seconds (or a lot more), depending on heap size and complexity.

    Tool was developed for lack of a method to inspect the heap or create a dump using Unity3D, as:
    • The builtin profiler only tracks objects inheriting from UnityEngine.Object
    • Can't seem to use the 3rd party memory dump tools from visual studio or monodevelop with unity
    • Can't seem to use the profiling functionality of mono, as one can't pass the required arguments (would require mono rebuild/hack)
    • The experimental Memory Profiler from Unity3D only works with IL2CPP (and standalone IL2CPP is not available yet)
    Output format
    Example of a small class with 3 static fields:

    Code (CSharp):
    1. Static (Players): 720 bytes
    2.     loadedPlayers (System.Collections.Generic.Dictionary`2[NetworkID,Players+Player]) : 588
    3.         valueSlots (Players+Player[]:12) : 184
    4.             0 (Players+Player) : 56
    5.         keySlots (NetworkID[]:12) : 132
    6.         linkSlots (System.Collections.Generic.Link[]:12) : 120
    7.         table (System.Int32[]:12) : 72
    8.     connectedPlayers (System.Collections.Generic.List 1[Players+Player]) : 104
    9.         _items (Players+Player[]:4) : 72
    10.     PlayerHasID (System.Func 3[Players+Player,NetworkID,System.Boolean]) : 24
    Example of a small assembly summary (this example is not a sensible usecase I guess, but it's small so: )

    Code (CSharp):
    1. Assembly: System.Core, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e of total size: 13684
    2.     Type: System.Security.Cryptography.AesTransform of size 9092
    3.     Type: Consts of size 4528
    4.     Type: System.Linq.Expressions.ExpressionPrinter of size 32
    5.     Type: System.Linq.Expressions.Expression of size 24
    6.     Type: System.TimeZoneInfo of size 4
    7.     Type: System.Threading.ReaderWriterLockSlim of size 4
    A summary of the results is available at %projectroot%/dump/log.txt. This contains all Types and Components parsed and Errors at the end. The summary lists Types in order of size, by order of total Assembly size.
    • Unity3D code Assemblies are printed to a file in the form of %projectroot%/dump/statics/%assembly%/%size%-%type%.
    • Other Assemblies are printed to a file at %projectroot%/dump/statics/misc/%size%-%type%.
    • Unity object results are printed to %projectroot%/dump/uobjects/%size%-%type%
    • Unity scriptableObject results to %projectroot%/dump/sobjects/%size%-%type%
    Every file starts with the Types total summed size or all static references (or instance in case of unity objects).
    • A 'normal' reference is printed in the following format: %fieldName% (%type%) : %totalSize%.
    • An Array is printed like: %fieldName% (%type%:%arraySize%) : %totalSize%. An array item has its index as %fieldName%.
    Indented afterwards are all object fields associated with the instance. Value type fields are not listed individually, but their size is included in the parent. Unless the value type is a struct with references to objects; those are listed.

    Settings
    Not much, but there are 3 constants in the main file; TYPE_MIN_SIZE_TO_PRINT, minimum byte count required before the type is printed to log.txt ROOT_MIN_SIZE, minimum byte count to create a file for the type CHILD_MIN_SIZE, minimum byte count to print the reference itself inside of the file (this is the main variable to tweak for scaling output size)

    Issues
    Total tracked memory count can be lower than the used heap size; No idea where Its missing objects or calculating incorrectly. Seems to miss about 10-30%. Various Types throw errors due to having bad implementations for GetHashCode() or Equals (Object). Parsing of the root Type causing the error is currently stopped, and parsing of the next Type is started. (This may actually be the cause for the missing size)

    Credits
    Idea/code was vaguely inspired by https://github.com/Cotoff/UnityHeapEx , but that code took multiple minutes to dump and created a 500 MiB .xml file for my use case, which was not really usable.
     
    Dmitry-Fofanov, KyleOlsen and Marked like this.
  2. onehand

    onehand

    Joined:
    Dec 3, 2015
    Posts:
    8
    Thanks @Zuntatos ! I found this useful and easy to setup!
     
  3. Zuntatos

    Zuntatos

    Joined:
    Nov 18, 2012
    Posts:
    612
    No problem! It seems the mono upgrade in unity 2017.1 will allow use of modern mono debugging tools, there's probably a proper 'memory explorer' thing in there (haven't tested/researched it a lot, stuck on 5.5 atm).
     
  4. GloriaVictis

    GloriaVictis

    Joined:
    Sep 1, 2016
    Posts:
    133
    Hello,
    Any chance you were trying to use it on 2017.4? Seems to be crashing for us while running at build. Any chance you could recommend an good mono debugging tool which could actually connect into running application ?
     
  5. Zuntatos

    Zuntatos

    Joined:
    Nov 18, 2012
    Posts:
    612
    https://bitbucket.org/Unity-Technologies/memoryprofiler/src/default/
    • Make sure you're running Unity 5.3a4 or later for IL2CPP support.
    • Make sure you're running Unity 2017.3.0b1 or later for Mono .NET 3.5 support.
    I assume there's also .NET 4.6 support, but I've not tested the tool yet. When I made this I tried a variety of tools but none worked. Haven't tested any since besides visual studio's unity debugger (you can explore some data when paused and attached)
     
  6. GloriaVictis

    GloriaVictis

    Joined:
    Sep 1, 2016
    Posts:
    133
    Thank you, we have been trying to use this tool in our project, but sadly its working only on small scenes. When we are trying to do a snapshot of a server scene it hangs out (and didnt proceed even after waiting 24 hours). Same thing happens using vanilla unity profiler snapshot. Any chance you had experienced like that before?

    I guess only chance to do that would be to somehow merge this project into our and launch this scene using editor and than doing snapshot. I am not sure if we will be able to merge that project into a working game project actually.