Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unity Board Game AI Causing Memory Leak

I am creating a board game similar to tic tac toe, and I've created an AI to play that game. The AI is very CPU intensive, so I decided to put it on it's own thread. I'm using this plugin to do multithreading: https://www.assetstore.unity3d.com/en/#!/content/15717 .

I have this IEnumerator:

static IEnumerator executeAITurn(Turn turn) {
    Vector2[] move = mctsManager.mcts(new State(sections, null, turn), AIIterations)[0, 0].metaData.lastMove;

    yield return Ninja.JumpToUnity;

    input(move, true);

    yield return Ninja.JumpBack;

    Debug.Log("DONE!");
}

and I run it using

gameManager.StartCoroutineAsync(executeAITurn((AITurn == Turn.X) ? Turn.O : Turn.X));

Normally when I run executeAITurn it works normally without problems, but for some reason sometimes when I run it, it does what it's supposed to but in task manager my memory just starts to increase by like 30 mb / sec. The memory increases all the way to 1000 mb and the game gets really slow. When I turn off play mode, the memory sometimes continues to increase or just stops where it is. I have to end Unity through task manager to free the memory.

One thing I've tried is replacing foreach loops with regular for loops and that seemed to help. The rate at which the memory was increasing decreased by a lot(initially it would increase at around 100 mb / sec).

Any help would be appreciated.

Here's some of the code involved in executeAITurn:

mctsManager Class: https://pastebin.com/yzeHrY2p

input Function: https://pastebin.com/8f2hzZws

like image 988
Bhaskar Avatar asked Aug 26 '17 15:08

Bhaskar


People also ask

What causes memory leaks unity?

Memory leaks typically happen because of one of two issues: An object is not released manually from memory through the code. An object stays in memory because of an unintentional reference.

What causes memory leaks in games?

This is known as a memory leak, and it happens when software fails to manage the available RAM correctly. With the computer functioning normally, RAM gets used by software in a dynamic fashion, and memory resources are allocated as needed.

What is Oracle database memory leak?

Answer: As a refresher, a memory leak is a condition where an application program (or the database software) allocates RAM resources and then fails to release the RAM from the heap.

How do you pinpoint memory leaks?

The primary tools for detecting memory leaks are the C/C++ debugger and the C Run-time Library (CRT) debug heap functions. The #define statement maps a base version of the CRT heap functions to the corresponding debug version. If you leave out the #define statement, the memory leak dump will be less detailed.


4 Answers

This sounds more like a garbage collection issue. I looked at your code for MCTS and noticed the following.

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {

This was missing from your first code, C# Input functions. Basically, this is invoking an update function. As you may notice, it says update function is called once per frame. Refer to this https://unity3d.com/learn/tutorials/topics/performance-optimization/optimizing-garbage-collection-unity-games

I would recommend a cache.

Hope that helps.

like image 156
Robert Livingston Avatar answered Oct 21 '22 18:10

Robert Livingston


First task manager is not a valid tool to measure Performance of even memory demand. The figures can be both way to high and way to low. Possibly at the same time.

Secondly, the very nature of the Garbage Collector makes measuring how much memory is actually used really tricky. The GC will try to run as little as possible. And if it only runs on application closure, that is the ideal case.

If you have excluded that it is any of those two common misconceptions, usually memory leaks in a Managed Runtime mean one thing: You add something to a Collection (array, List<>, Dictionary<,>) but forget to take it out again. That is the only way a memory leak can happen. In particular GC is there so we do not run into the "I forgot to free memory" problem ever again.

A rarer case is mistakes with Disposing. If you hande umanaged resources directly you should be writing your finalizer first, Dispose second. If you handle anythign that implements IDisposeable, always also implement IDisposeable even if all your Dispose() does is relay the order to the contained instance. Never relay a Finalize order, that is between that instance and the GC.

like image 23
Christopher Avatar answered Oct 21 '22 19:10

Christopher


When dealing with memory leaks, you have to be very careful, because every step in your application is important.

For beginners, every loop you have, may cause an increase in memory. Try reversing from using loops, to working with dictionary and hash table, it will cost you with 'out-of-order' data, since it is comparing hash codes, but I don't think you need a certain order for your data in the game.

Clarification: Every list of array that you have, if you know the exact size of your array, use ArrayList. If you use list, switch it to dictionary, if the type of the list is known to you or Hash Table if not. this way you will be able to get the information in a key - value way, which is faster and improves performance.

Second, try use the Using syntax when ever you instantiate a new object, this will help you implement iDisposable interface to dispose of objects more effectively.

Third, Prevent your code from boxing variables as much as you can! boxing means, the process of storing a value type in the heap instead of in the stack, so in the stack you only have a reference to the variable's location.

Fourth, use tools to monitor you code and check for possible memory leaks in your applications. There are a lot of tools except for the profiler out there so just search for it and you will find something to help you.

like image 38
Barr J Avatar answered Oct 21 '22 20:10

Barr J


All of the answers to this question really helped me better manage memory. I just thought I'd summarize the big things from each in one question.

First of all, in Robert Livingston's answer he mentions this article: https://unity3d.com/learn/tutorials/topics/performance-optimization/optimizing-garbage-collection-unity-games, which literally covers everything that helped me. I wish I had read that before hand.

Anyways, the three biggest things that helped me were avoiding boxing, clearing lists, and caching (All three of which are mentioned in the article). Trying to avoid boxing also led me to do research on the difference between value-types and reference-types, which led me to change two of my classes to structs, which helped with memory.

The biggest help to memory was probably clearing lists, as they were being created very frequently, but I wasn't clearing them causing a lot of garbage to build up. (This is why I gave the bounty to the person who mentioned clearing lists).

Anyways, thanks for all the help.

like image 34
Bhaskar Avatar answered Oct 21 '22 19:10

Bhaskar