2

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

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

问题在于这是一个可变大小的数组,需要将它传递给 slimdx,它会在其上调用 GCHandle.Alloc。由于它的大小可变,因此可能必须调整大小才能重用它。我也不能只为每个区域分配一个最大大小的数组,因为它需要大量的内存。由于与 slimdx 的 GCHandle 业务,我无法使用列表。

到目前为止,仅在需要更大时调整数组的大小似乎是我唯一可行的选择,但它可能效果不佳,实施起来可能会很痛苦。我需要单独跟踪数组的实际大小,并使用不安全的代码来获取指向数组的指针并将其传递给 slimdx。它最终也可能最终使用大量内存,以至于我不得不偶尔将所有数组的大小减小到所需的最小值。

我犹豫要不要跳过这个解决方案,并想知道是否有人对此有更好的解决方案。

4

3 回答 3

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 的使用有些奇怪,因为我总是必须使用偏移量和索引,它的行为不是常规数组。相反,您可以提取自己的结构,该结构允许基于零的索引,这更容易使用,但代价是每个基于索引的访问都会花费您并添加基本偏移量。但是,如果使用模式主要是 foreaches 那就没关系了。

我遇到过 ArraySegment 也太昂贵的情况,因为您确实每次都分配一个结构并按堆栈上的值将其传递给所有方法。您需要密切关注它的使用情况是否正常,以及它是否没有以过高的速率分配。

于 2012-07-08T05:45:18.417 回答
1

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

于 2012-07-06T22:54:54.507 回答
0

我对您对旧库 slimdx 的问题表示同情,它可能不兼容 .NET。我处理过这样的情况。

建议:

  1. 使用性能更高效的通用列表或数组,如 ArrayList。它会跟踪数组的大小,因此您不必这样做。一次分配列表,块,例如一次 100 个元素。
  2. 使用 C++ .NET 并利用不安全数组或 .NET 类(如 ArrayList)。
  3. 更新:使用虚拟内存的想法。将一些数据保存到 XML 文件或 SQL 数据库中,从而减轻大量内存。

我意识到无论哪种方式都是一场赌博。

于 2012-07-07T00:46:39.130 回答