Unity Board游戏AI导致内存泄漏

时间:2017-08-26 15:28:56

标签: c# multithreading unity3d memory-leaks

我正在创建一个类似于tic tac toe的棋盘游戏,我已经创建了一个AI来玩该游戏。 AI非常占用CPU,所以我决定把它放在它自己的线程上。我正在使用这个插件进行多线程处理:https://www.assetstore.unity3d.com/en/#!/content/15717

我有这个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!");
}

我用

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

正常情况下,当我运行executeAITurn时,它可以正常工作而没有问题,但由于某些原因,有时当我运行它时,它会按预期执行,但在任务管理器中,我的内存开始增加30 mb / sec。内存一直增加到1000 MB,游戏变得非常慢。当我关闭播放模式时,内存有时会继续增加或只是停在原地。我必须通过任务管理器结束Unity以释放内存。

我尝试过的一件事是用常规for循环替换foreach循环,这似乎有所帮助。内存增加的速度下降了很多(最初会增加到大约100 mb /秒)。

任何帮助都将不胜感激。

以下是executeAITurn中涉及的一些代码:

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

输入功能:https://pastebin.com/8f2hzZws

4 个答案:

答案 0 :(得分:3)

这听起来更像垃圾收集问题。我查看了MCTS的代码并注意到以下内容。

    // Use this for initialization
    void Start () {

    }

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

您的第一个代码C#输入函数中缺少这个。 基本上,这是调用更新功能。您可能会注意到,它表示每帧调用一次更新功能。请参阅此https://unity3d.com/learn/tutorials/topics/performance-optimization/optimizing-garbage-collection-unity-games

我建议使用缓存。

希望有所帮助。

答案 1 :(得分:2)

在处理内存泄漏时,您必须非常小心,因为应用程序中的每一步都很重要。

对于初学者来说,每个循环都可能会导致内存增加。 尝试从使用循环转换到使用字典和散列表,它将花费你“无序”数据,因为它是比较哈希码,但我不认为你需要一个特定的数据顺序游戏。

<强>澄清: 您拥有的每个数组列表,如果您知道数组的确切大小,请使用ArrayList。如果您使用列表,请将其切换为字典,如果您知道列表的类型,或者如果不知道则使用哈希表。通过这种方式,您将能够以键值方式获取信息,从而更快速地提高性能。

其次,在实例化新对象时尝试使用Using语法,这将帮助您实现iDisposable接口以更有效地处理对象。

第三,尽可能多地阻止你的代码装箱变量! boxing意味着,在堆中而不是在堆栈中存储值类型的过程,因此在堆栈中,您只能引用变量的位置。

第四,使用工具监视代码并检查应用程序中是否存在可能的内存泄漏。 有很多工具,除了探查器,所以只需搜索它,你会找到一些东西来帮助你。

答案 2 :(得分:2)

第一个任务管理器是衡量偶数memory demand的效果的有效工具。这些数字既可以是高,也可以是低。可能在同一时间。

其次,Garbage Collector的本质使得测量实际使用的内存真的很棘手。 GC将尝试尽可能少地运行。如果它仅在应用程序关闭时运行,那么这是理想的情况。

如果您排除了这两种常见误解中的任何一种,通常在托管运行时中的内存泄漏意味着一件事: 您向Collection(数组,List&lt;&gt;,Dictionary&lt;,&gt;)添加内容但忘记再次将其删除。这是内存泄漏发生的唯一方法。特别是GC就在那里,所以我们不会遇到&#34;我忘了释放记忆&#34;问题再一次。

一个罕见的案例是Disposing的错误。如果您直接处理非管理资源,则应首先编写终结器,然后再处理。 如果您处理实现IDisposeable的anythign,即使所有Dispose()都将订单中继到包含的实例,也始终实现IDisposeable。切勿中断Finalize订单,即该实例与GC之间的订单。

答案 3 :(得分:1)

这个问题的所有答案确实帮助我更好地管理记忆。我只是想在一个问题中总结每个问题。

首先,在Robert Livingston的回答中,他提到了这篇文章:https://unity3d.com/learn/tutorials/topics/performance-optimization/optimizing-garbage-collection-unity-games,它实际上涵盖了帮助我的一切。我希望我之前已经阅读过。

无论如何,帮助我的三件最重要的事情就是避免拳击,清除列表和缓存(文章中提到了所有这三个)。试图避免拳击也让我研究了值类型和引用类型之间的区别,这导致我将我的两个类改为结构,这有助于记忆。

对内存的最大帮助可能是清除列表,因为它们是非常频繁地创建的,但是我没有清除它们导致大量垃圾堆积。 (这就是为什么我把奖金给了提到清算单的人。)

无论如何,感谢所有的帮助。