Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

关于C#版本Agent实例的内存泄漏问题 #140

Open
MysteryAngle opened this issue Sep 23, 2021 · 3 comments
Open

关于C#版本Agent实例的内存泄漏问题 #140

MysteryAngle opened this issue Sep 23, 2021 · 3 comments

Comments

@MysteryAngle
Copy link

Agent类在析构函数的时候调用了以下的代码:

Context.RemoveAgent(this);

Context中持有agent实例的引用,同时这个Context实例又被一个静态字典所引用(Context.ms_contexts),因此析构函数应该永远不会被执行才对。

目前的解决办法是在不需要Agent实例的时候,手动调用以下两个方法:

agent.btunloadall();
Context.RemoveAgent(agent);

另外记得把条件编译符号BEHAVIAC_RELEASE声明一下,因为调试模式下会导致实例被保存到一个静态变量中。

我不知道目前是否还有更好的做法,但是没有更新的情况下只能暂时这样做了,如果有其他的解决办法劳烦告知一下。

@MysteryAngle
Copy link
Author

进一步分析,在Workspace这个类里面创建行为树的时候,如下代码:

public BehaviorTreeTask CreateBehaviorTreeTask(string relativePath)

该方法使用了一个成员变量m_allBehaviorTreeTasks来保存所有创建的行为树实例:

// ...
// 创建行为树实例
BehaviorTask task = bt.CreateAndInitTask();
Debug.Check(task is BehaviorTreeTask);
BehaviorTreeTask behaviorTreeTask = task as BehaviorTreeTask;

if (!m_allBehaviorTreeTasks.ContainsKey(relativePath))
{
    m_allBehaviorTreeTasks[relativePath] = new BTItem_t();
}

BTItem_t btItem = m_allBehaviorTreeTasks[relativePath];

//
// 这里实际上永远返回true,因为新的实例肯定在之前是没有保存的
if (!btItem.bts.Contains(behaviorTreeTask))
{
    btItem.bts.Add(behaviorTreeTask); //  这里保存了行为树实例
}

同之前的Context一样,由于Workspace是单例的,因此如果没有从btItem.bts变量里面移除掉的话,实例将不会被释放。
正常来说如果Agent被销毁了,会调用Workspace.DestroyBehaviorTreeTask方法来移除,但是有一个情况例外,那就是如果一个行为树使用了子树,那么这个子树并不会进行释放操作,从而导致了行为树实例不断增长,最终导致内存耗尽。

经过我们的场景分析,将行为树实例保存到Workspace中好像并没有什么用途,因此简单粗暴的解决办法就是,移除掉这些代码,通过内存分析工具观察,可以正常的被释放掉。

@tanghuipang
Copy link

我这里遇到一个相似的问题。
Base/Utils.cs里面有这样一个方法

      private static string ReadToken(string str, int pB, int end)
      {
          string strT = "";
          int p = pB;

          while (p < end)
          {
              strT += str[p++];
          }

          return strT;
      }

看起来跟直接用str.SubString(pB, end - pB) 是一样的效果,不同的是这样处理会多出大量GC

@cuixin
Copy link

cuixin commented Jun 10, 2022

我这里遇到一个相似的问题。 Base/Utils.cs里面有这样一个方法

      private static string ReadToken(string str, int pB, int end)
      {
          string strT = "";
          int p = pB;

          while (p < end)
          {
              strT += str[p++];
          }

          return strT;
      }

看起来跟直接用str.SubString(pB, end - pB) 是一样的效果,不同的是这样处理会多出大量GC

C#能写出这种代码不太可能,严重怀疑是cpp写完自动转换的,还有很多while(e.MoveNext)这种写法。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants