Dar*_*rcy 3 .net c# garbage-collection list
我正在开发一个带有大量AI的游戏,并注意到我的垃圾收集器每秒收集3-4次物体,这真的会伤害性能并在帧速率下降之前将敌人的数量限制在120.我分析了代码并发现罪魁祸首是我的碰撞检测代码,其中我有一个函数被调用多次,一个帧生成一个投影到轴上的列表.代码就像
public List<Vector2> foo()
{
List<Vector2> projections = new List<Vector2>();
// Calculate and return projections
}
Run Code Online (Sandbox Code Playgroud)
还有一些其他函数也在每次调用时创建新列表,并且我每个函数调用都会生成新列表,支持将一个vector2s列表存储为类的字段,这样我就不会调用每个函数的新列表呼叫.这将垃圾收集呼叫从每秒3-4次减少到每10-20秒一次,这使得我可以在帧率下降之前在地图上获得400-500个敌人.
新功能看起来像:
public List<Vector2> foo()
{
// projections is now a field of this class so we just clear it each function call
projections.Clear();
// Calculate and return projections
}
Run Code Online (Sandbox Code Playgroud)
我的问题是为什么List.Clear方法比List = new List()招致更少的垃圾收集?当你调用clear时,我已经对列表中的项发生了什么进行了一些研究,当它们没有引用时看起来好像它们应该被垃圾收集,所以我的项目正在函数内创建,所以当函数退出时并且下次调用清除列表,以前的项目是否也应该被垃圾收集?
我的理解是,清除的项目应该是垃圾收集,就像我调用List = new List一样.很明显,当我切换到List.Clear()时,我的垃圾收集量大大减少了.以下是我用来试图了解我的列表项中发生的事情的链接.
当您清除列表时,您只需将计数设置为0并擦除现有内容(这使得旧对象可能是可收集的,如果它们是引用类型).保留现有的buffer(T[]),可以重用于下一组.我猜你每帧通常有大致相同数量的投影,这意味着相同的数组可以永远使用
但是:如果你是新的,那么会分配一个新的默认大小的缓冲区 - 它从10或20,IIRC开始(编辑:现在看起来像是4).当你添加(Add)项时,每当它用完房间时,就必须调整缓冲区的大小(它使用加倍算法,因此当你添加第21项时,它会加倍到40,等等).如果你有很多预测,这可能意味着分配(并重新复制)很多次 - 所以你可以分配一堆最终被丢弃的数组......当然还有单个列表对象.
这些丢弃的"当它变满时将它加倍"缓冲区大小为4,8,16,32,64,128,256,512,1024等 - 加上实际的列表对象本身 - 你看到被收集; 不是你的游戏对象.
特别Vector2是:struct我相信是 - 所以:没有什么可收集的!
这真的可以加起来!