关于C#版本Agent实例的内存泄漏问题
Agent类在析构函数的时候调用了以下的代码:
Context.RemoveAgent(this);
Context中持有agent实例的引用,同时这个Context实例又被一个静态字典所引用(Context.ms_contexts),因此析构函数应该永远不会被执行才对。
目前的解决办法是在不需要Agent实例的时候,手动调用以下两个方法:
agent.btunloadall();
Context.RemoveAgent(agent);
另外记得把条件编译符号BEHAVIAC_RELEASE声明一下,因为调试模式下会导致实例被保存到一个静态变量中。
我不知道目前是否还有更好的做法,但是没有更新的情况下只能暂时这样做了,如果有其他的解决办法劳烦告知一下。
进一步分析,在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中好像并没有什么用途,因此简单粗暴的解决办法就是,移除掉这些代码,通过内存分析工具观察,可以正常的被释放掉。
我这里遇到一个相似的问题。 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
我这里遇到一个相似的问题。 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)这种写法。