Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question OutOfMemory exception on Development Build, Log file says it's due to Profiler? How to tackle this?

Discussion in 'Scripting' started by TheGameNewBie, May 10, 2023.

  1. TheGameNewBie

    TheGameNewBie

    Joined:
    Jul 27, 2017
    Posts:
    92
    I am working on a project which currently has a Hex terrain generator and a path finding system in it, nothing much. After playing the game for a while, it throws an OutOfMemory error, which freezes the game for a while and then resumes.
    I've tried profiling in both Editor and Development builds, the error occurs on both platforms.
    The weird thing being that memory usage does not increase steadily, rather it spikes up in one instant.
    Initially, it stays at around 0.5 GB, I play the game for a while and there's not much change. But then suddenly the game freezes and once it resumes, the memory usage has spiked to 4.5 GBs.
    In the profiler, most categories show a slight increase but most notably, the 'Managed Heap' increases a lot. Going from 4 MB at the start to 2.3 GBs at end most of which shows up as Fragmented Memory Space.

    But If i look at the log in the development build, it says this,
    OutOfMemory Log.PNG
    It seems the error occurs due to profiler?
    Memory snapshots don't work after the spike has occured. I can take a snapshot but that snapshot just won't open to see what's inside it.
    I am confused as to what might be causing this, Is it something in the written code? Or is this related to the profiler? Also, why does it spike up in an instant as opposed to increasing over time?

    If it is due to the code I wrote, where can I start to debug this? As I said, memory profiler does not work after the spike so I cannot figure out what might be causing it. I am already using pooling for Lists, Gameobjects and such.

    Any help?
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,756
    Sigh... this is one of the problems with instrumented code: it always takes more memory. That's why most console development systems have extra RAM to allow profiling when developing the game, while still keeping the final console memory low and cheap to manufacture.

    When you write this:

    and this:

    it sounds like perhaps you're trying to pathfind on something that is far too massive to reasonably do. Pathfinding isn't magic, it's just a "best way" to try and find a destination in a graph. If your graph has thousands or millions of entries, traversing it in a meaningful way is going to (at least) require that much work.

    Solutions to this include time-slicing each pathfinding attempt, eg, only iterating some number of steps per frame. This will still ultimately require the same massive amount of memory, but in theory you can control the consumption better, perhaps by only allowing a single agent to pathfind at a time.

    The ultimate solution for arbitrarily large pathfinding grids will be for you to embed knowledge into the grid to help the system, such as implementing a dual-level macro- and micro- navigation mesh, something with large connected areas, and then within each connected area a smaller finer-grained mesh.

    It's sort of like highway/freeway driving. If you're driving from city A to city B, you only need to get to the highway in City A, then get on the highway and get off at City B, and find your local destination. No matter how many tiny cities along the way you have, you don't care about what is in them because you don't go in there.
     
  3. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,528
    While it's true that the profiler does add quite a bit of overhead (especially when using deep profiling), however what makes you think that the profiler is responsible for your out of memory issue? You run out of memory inside HexPathFinder when it tries to resize a generic List. Since you said that the memory "suddenly" spikes after a longer freeze, it just indicates that, as Kurt said, you probably try to path find something impossible and it may floodfill your whole map.

    Pathfinding can get really expensive. Though of course it's possible that you have a flaw in that path finding code. I actually wrote a 3d path finder in lua for a computercraft turtle in minecraft. It was a program to completely drain a lava lake. Of course it doesn't have the whole map available but essentially build it as it goes and detects its environment. However if it needs to move from one dead end to the other side of a large lake (say 100 blocks) through a more or less complex cave structure, the path finding can take several seconds (I had to insert yields, otherwise the game would have shut down my program as it would be considered hanging ^^). I'm sure I also consumed a lot of extra GB just for holding the pathfinding data. Really fun when playing on a server and a single turtle could tank the whole server :p

    We don't know if that list that is resized there is the actual issue or if the memory is wasted somewhere else. It's always difficult to debug such systems because complex or recursive search algorithms can't be "stepped" through and deep profilting an algorithm which may have millions or billions of calls usually crashes the profiler. What usually helps is to add some statistics to the algorithm. For example when you're doing A*, track the highest element count in the open list. If it's a recursive algorithm, track the deepest nesting depth.
     
    Kurt-Dekker likes this.
  4. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,528
    Well, this could actually be part of the problem ^^. What kind of lists do you pool and how many and what's the capacity of those pooled lists? The capacity of a list never decreases, at least not automatically. It can only grow when it's necessary. So if you're using a pool of lists and you may stress your lists so they have to go into the millions, keeping several such lists may not be a good idea after all.
     
    Kurt-Dekker likes this.
  5. TheGameNewBie

    TheGameNewBie

    Joined:
    Jul 27, 2017
    Posts:
    92
    So, I tried finding the issue, but no luck. In the end, I just redid the pathfinding code and it works fine.

    I agree. But the game map I was testing on was a 4x4 map. So, I don't think the number of entries were causing the massive memory usage.
    I actually did not set a capacity on the lists. (I did not know capacity had an effect on memory allocation).
    Agree, But as I said, the maximum number of cells on the map were 16. So, the issue probably wasn't due to the number of entries.

    I'm trying to create a Civilization-esque system. Where it's Turn based and at any moment, only one pathfinding operation is going on. Previously, I used the A* algorithm where it would take 2 cells and try to find the path between them. But I also wanted to show all the possible cells where the unit can move in that turn, and for that I had to use Breadth First search. So I ditched A* and used BFS for pathfinding as well. The issue does not occur anymore so the problem was definitely in the A* algorithm. But I don't exactly know where, I'm sure I've overlooked it somewhere.

    Anyway, I did learn a bit about memory management, also ran into 'Serialization depth limit exceeded' along the way, so there's that. :)
    Thanks for the help.