在这种情况下如何减少垃圾的产生

时间:2012-07-06 22:39:00

标签: c# garbage-collection slimdx

我的游戏已经达到了产生过多垃圾的程度,导致GC时间过长。我一直在四处走动,减少了大量的垃圾产生,但有一个地方过于频繁地分配了大量的内存而且我仍然坚持如何解决这个问题。

我的游戏是一个类似于我的游戏世界,当你走路时会产生新的区域。我有一个大的,可变大小的数组,在创建一个新区域时分配,该区域用于存储地形的顶点数据。在数组填充数据后,它将传递给slimdx DataStream,以便可以用于渲染。

问题是这是一个可变大小的数组,需要传递给slimdx,它会调用GCHandle.Alloc。由于它的大小可变,因此可能需要调整大小以便重用它。我也不能为每个区域分配一个最大大小的数组,因为它需要不可能的大量内存。我不能使用List,因为GCHandle业务有slimdx。

到目前为止,仅在需要更大的时候调整阵列大小似乎是我唯一合理的选择,但它可能不会很好,并且可能会很难实现。我需要分别跟踪数组的实际大小,并使用不安全的代码来获取指向数组的指针并将其传递给slimdx。它最终可能最终会使用我偶尔需要的大量内存,并将所有阵列的大小减少到所需的最小值。

我对于跳过这个解决方案犹豫不决,想知道是否有人看到了更好的解决方案。

3 个答案:

答案 0 :(得分:1)

我建议与slimdx库更紧密地集成。它是开源的,因此您可以深入挖掘并找到渲染所需的关键路径。然后,您可以通过使用DMA风格的内存共享方法进行整合。

答案 1 :(得分:1)

由于SlimDX是开源的,而且速度太慢,现在是时候改变开源以满足您的性能需求了。我在这里看到的是你想要保留一个更大的数组,但只向实际使用的区域传递给SlimDX,以防止为这个可能很大的数组增加内存分配。

.NET Framework中有一个名为ArraySegment的类型,它是为此目的而制作的。

// Taken from MSDN
// Create and initialize a new string array.
String[] myArr = { "The", "quick", "brown", "fox", "jumps", "over", "the", 
                   "lazy", "dog" };

// Define an array segment that contains the middle five values of the array.
ArraySegment<String> myArrSegMid = new ArraySegment<String>( myArr, 2, 5 );


public static void PrintIndexAndValues( ArraySegment<String> arrSeg )  
{
   for ( int i = arrSeg.Offset; i < (arrSeg.Offset + arrSeg.Count); i++ )  
   {
        Console.WriteLine( "   [{0}] : {1}", i, arrSeg.Array[i] );
   }
   Console.WriteLine();
}

那说我发现ArraySegment的用法有些奇怪,因为我总是要使用偏移和索引,它只是表现不是常规数组。相反,你可以提炼自己的结构,它允许基于零的索引,这更容易使用,但代价是每个基于索引的访问都会花费你并添加基本偏移量。但如果使用模式主要是预告,那么它并不重要。

我遇到过ArraySegment也太昂贵的情况,因为你每次都会分配一个结构,并通过堆栈上的值传递给所有方法。你需要仔细观察它的使用情况,以及它是否以过高的速度分配。

答案 2 :(得分:0)

我同情你的问题与较旧的库,slimdx,可能不符合.NET。我处理过这种情况。

建议:

  1. 使用性能更高的通用列表或数组,如ArrayList。它跟踪阵列的大小,因此您不必这样做。一次分配列表,例如块,例如一次100个元素。
  2. 使用C ++ .NET并利用不安全的数组或像ArrayList这样的.NET类。
  3. 已更新:使用虚拟内存的想法。将一些数据保存到XML文件或SQL数据库,减少了大量内存。
  4. 我意识到这是一场赌博。