【问题标题】:Mutable strings in WP7 C#/XNA?WP7 C#/XNA 中的可变字符串?
【发布时间】:2011-09-08 18:00:47
【问题描述】:

我正在开发一款 Windows Phone 7 XNA 游戏。它是用 C++ 编写的游戏的移植版本,因此,我尝试尽可能少地重写游戏代码。

垃圾在 WP7 上是一个巨大的问题,因为收集器是非分代的并且速度很慢,所以收集(每 1MB 触发一次)每 MB 分配大约需要 10 毫秒。我完全打算使用最大 90MB 的可用空间,因此我们正在查看每 MB 分配约 900 毫秒的延迟。

我已经能够重做一些事情,这样我们就不会在每帧产生垃圾,除了少数字符串。

看来StringBuilder.ToString()会产生垃圾,here描述的方法在WP7上不起作用。

我需要做的两件事是:

  • 将分钟/秒/百分位格式化为 mm:ss.hh 以显示在屏幕上。显然,我可以使用 StringBuilder 来做到这一点(使用不会通过装箱 int 产生垃圾的扩展方法)并直接使用 SpriteBatch 显示 StringBuilder。
  • 将格式为“foo.bar.baz.qux”的字符串拆分为 '.' 上的数组,即 {"foo", "bar", "baz", "qux"} 并复制一个元素到时间到一个字符串数组。这是为了设置游戏角色的层次状态。它也几乎直接从原始游戏移植而来,并且在很大程度上取决于它以这种方式工作。我真的很想避免重写它。

没有将大量代码转换为使用 char[] 而不是字符串,有没有办法在 C# 中拥有真正无垃圾的可变字符串?

【问题讨论】:

标签: c# windows-phone-7 garbage-collection xna


【解决方案1】:

为什么首先需要将StringBuilder 转换为String?正如您所指出的,您可以将StringBuilder 直接传递给XNA 的绘图方法。您也可以使用StringBuilder 来检索子字符串:

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

你想要避免使用StringBuilder 的唯一事情是ToString()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;
}

【讨论】:

  • 格式化非字符串对象(例如:数字)会产生垃圾(它调用它们的ToString 方法)。但是编写一个无垃圾的扩展方法来附加整数(或大多数其他类型,真的)是非常简单的。您可以很容易地在网上找到示例。
  • 快速浏览反编译的源代码确认您是正确的。我不知道为什么我不这么认为。但是,是的,您可以解决这个问题。
【解决方案2】:

我正在尝试尽可能少地重写游戏代码。

请注意,重写可能需要更长的时间。 Cole Campbell 是对的,当你想绘制它时调用 ToString() 是没有意义的。 XNA 有使用 StringBuldier 的 draw 方法,它在我的游戏中运行良好。

解决您的问题的另一种方法:为您的字符串创建一个全局 HashSet,并在您加载游戏或关卡时设置它以避免收集压力。

在加载游戏时尽可能多地尝试。

【讨论】:

    猜你喜欢
    • 2015-04-15
    • 2020-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-22
    • 2020-10-15
    • 1970-01-01
    相关资源
    最近更新 更多