我正在编写一个模拟,它有一个每帧调用的更新循环。在更新功能中,我有数百万个对象要更新,所以它看起来像这样。
public void Update(float deltaTime)
{
Time += deltaTime;
foreach (SimulationObject obj in objects.ToArray())
obj.Update(deltaTime);
}
where objects is
List<SimulationObject> objects = new List<SimulationObject>();
and is populated at program initialization time.
你可能会看到objects.ToArray()每帧都会复制这个巨大的列表,然后副本被垃圾收集。这会给我带来巨大的性能问题。对于大约2分钟的运行,收集的垃圾达到约2G。由于某些第三方库在后台异步修改了这些对象的列表,因此我似乎无法删除ToArray()。
我想知道是否有减少垃圾收集的好方法,是避免复制还是重复使用分配的空间?
我是C#的新手,并尝试寻找答案,但未能。如果这是一个重复的帖子,我道歉。
答案 0 :(得分:3)
ToArray()
在这里并不是必需的,只是浪费时间和记忆。使用for
循环。我会从像
for (int i = 0; i < objects.Count; i++)
{
SimulationObject obj = null;
try
{
obj = objects[i];
}
catch (ArgumentOutOfRangeException)
{
// something was removed from the collection
// we reached the end of the list
break;
}
obj.Update(deltaTime)
}
此代码故意拆分obj = objects[i]
和obj.Update(deltaTime)
,以避免在Update()
抛出ArgumentOutOfRangeException
时中断循环。
请注意两个事实:
objects
集合后会跳过第一次迭代,这实际上不应该是一个问题,因为它们的添加在设计上是异步的。objects
列表中删除后立即更新一次(当然,同时删除,但结果往往会在“)之后出现。”根据模拟情况,这种情况可能是不合需要的,可能需要一些特定的处理。答案 1 :(得分:-1)
没有理由拨打ToArray()
,因此您只需使用
public void Update(float deltaTime)
{
Time += deltaTime;
foreach (SimulationObject obj in objects)
obj.Update(deltaTime);
}
答案 2 :(得分:-1)
有人指出你不需要使用toArray()方法,因为它只会创建当前列表的副本。
如果我理解正确,您正在执行此操作,因为您的列表正在后台由第三方lib修改。
我认为在这种情况下你可以安全地使用Parallel.ForEach循环,因为你不是修改列表本身,只是列表中的项目。
Float Time; // some value
Float deltaTime; // some value
Parallel.ForEach(objects, currObject =>
{
// do stuff
Interlocked.increment(ref Time,deltaTime);
currObject.Update(Time)
}