2011-09-08 56 views
10

我正在開發Windows Phone 7 XNA遊戲。這是用C++編寫的遊戲的一個端口,因此,我儘可能少地重寫遊戲代碼。WP7中的可變字符串C#/ XNA?

垃圾是巨大問題在WP7上,因爲收集器是非代和慢的,所以一個集合(每1MB觸發一次)每MB分配大約需要10ms。我完全打算使用最大90MB的可用空間,因此我們正在尋找每MB分配約900毫秒的失速。

我已經能夠重寫的東西,使我們沒有垃圾產生的每幀,除了少數情況下的字符串。

看來StringBuilder.ToString()會生成垃圾,並且描述的方法here在WP7上不起作用。

的兩件事情我需要做的是:

  • 格式分/秒/ hundreths爲毫米:用於顯示屏幕ss.hh。顯然,我可以用StringBuilder來做到這一點(使用擴展方法,不會從裝箱內容中創建垃圾),並直接使用SpriteBatch顯示StringBuilder。
  • 將形式爲「foo.bar.baz.qux」的字符串拆分爲'。'即{「foo」,「bar」,「baz」,「qux」}中的一個數組,並將一個元素複製到時間轉換爲字符串數組。這是爲了設置遊戲角色的等級狀態。它也非常直接地從原始遊戲移植過來,並且相當一部分依賴於它以這種方式工作。我真的很想避免重寫它。

缺乏將大量代碼轉換爲使用char []而不是字符串,有沒有什麼辦法在C#中有真正的無垃圾可變字符串?

+2

只是一個側面說明芒果有Generational GC http://blogs.msdn.com/b/abhinaba/archive/2011/04/13/generational-gc-in-windows-phone-mango.aspx – Terrance

+0

此外,這是一種使某些東西「更接近」可變字符串的方法http://stackoverflow.com/questions/6913435/how-to-get-a-list-of-mutable-strings – Terrance

回答

10

爲什麼您需要首先將StringBuilder轉換爲String?如您所知,您可以直接將StringBuilder傳遞給XNA的繪圖方法。您還可以使用StringBuilder檢索子:

substringBuilder.Length = 0; 
for (int i = start; i <= end; i++) 
    substringBuilder.Append(originalBuilder[i]); 

要避免與 StringBuilderToString()AppendFormat()唯一的東西。其他格式化方法(據我所知)都沒有產生垃圾。 更新:我錯了。編寫你自己的擴展方法。可以在這裏找到一個簡明的例子:Avoiding garbage when working with StringBuilder

編寫一個方法會比較容易,它會根據給定的分隔符將字符串拆分爲子字符串。請記住,String.Split()是邪惡的兩個的原因 - 首先,因爲它分配新的字符串;第二,因爲它分配一個新的陣列。字符串的不變性只是你問題的一半。

請考慮以下擴展方法StringBuilder。我沒有徹底測試過這個代碼,但它應該給你一個大概的想法。請注意,它期望您傳入預先分配的數組,然後它將填充。

public static void Substring(this StringBuilder source, Int32 start, Int32 count, StringBuilder output) 
{ 
    output.Length = 0; 
    for (int i = start; i < start + count; i++) 
    { 
     output.Append(source[i]); 
    } 
} 

public static int Split(this StringBuilder source, Char delimiter, StringBuilder[] output) 
{ 
    var substringCount = 0; 
    var substringStart = 0; 
    for (int i = 0; i < source.Length; i++) 
    { 
     if (source[i] == delimiter) 
     { 
      source.Substring(substringStart, i - substringStart, output[substringCount]); 
      substringCount++; 
      substringStart = i + 1; 
     } 
    } 
    if (substringStart < source.Length - 1) 
    { 
     source.Substring(substringStart, source.Length - substringStart, output[substringCount]); 
     substringCount++; 
    } 
    return substringCount; 
} 
+1

格式化非字符串對象(例如:數字)將生成垃圾(它調用他們的'ToString'方法)。但是爲附加整數(或其他大多數類型)編寫一個無垃圾擴展方法非常簡單。你可以在網上很容易找到例子。 –

+0

快速瀏覽經反編譯的源代碼,確認您是正確的。我不確定我爲什麼會這麼想。但是,是的,你可以解決這個問題。 –

0

我想要做的遊戲性代碼儘可能少重寫。

小心,重寫可能需要更長的時間。科爾坎貝爾是正確的,當你想要繪製它時沒有必要調用ToString()。 XNA的繪製方法採用了StringBuldier,在我的遊戲中效果很好。

解決您問題的另一種方法:爲您的字符串創建全局HashSet,並在加載遊戲或關卡時設置它以避免收集壓力。

嘗試儘可能地加載遊戲時儘可能多地做。