7

所以我想将我的 PC 游戏转换为在 Xbox 360 上运行。它在 PC 上运行得非常好,配备 Intel Core 2 Quad @ 2.40Ghz 和 Radeon 4850 512MB。

我将它移植到 Xbox 上,马上就发现列表导入的不变性和继承存在一些问题,所以我简单地使用了称为 .Cast<>() 的 LINQ 方法。

如果这种方法开销很大,请告诉我,因为由于某种原因我无法在 360 上部署性能分析,很可能是因为它在 360 上播放。

然后另一个问题来了,这是一个很好的 System.OutOfMemoryException。我的天空盒纹理是 4096x4096,因此将它们减少一半可以消除该错误。奇怪的是,它们只有 3MB x 6,所以它不应该使用那么多可用的 512MB。

因此,当所有这些问题都被清除后,每 2 秒 1 帧的效果就被引入了。然后它在玩 1 分钟后崩溃,无论这意味着什么,它都是“代码 4”。

它像幻灯片一样播放。以下是来自 PC 游戏的一些性能分析图像。他们还不错。

CPU: http: //i.imgur.com/JYx7Z.png RAM: http: //i.imgur.com/C29KN.png 72% = 150MB 请注意。

我希望这里的任何人都对这个问题有一些经验。坦率地说,我全神贯注。

4

1 回答 1

10

性能问题的根本原因几乎可以肯定是因为您在游戏运行时分配内存(在启动之后,在Draw/Update循环期间)。

在 Windows 上,这很好。Windows 上的垃圾收集器是分代的(只会在可能的情况下清理新对象)并且速度极快。它也很聪明地选择了何时运行。

另一方面,Xbox 360 上的垃圾收集器完全是垃圾。它为每分配 1MB 的内存运行。它在运行时检查整个托管堆。而且启动速度很慢。

所以答案是永远不要在游戏处于运行状态时分配内存。

这里有一篇很好的博客文章。(它还描述了从不分配内存的替代方案 - 这是为了降低堆复杂性 - 这真的很难实现,我不推荐它。)

  • 您将不得不删除诸如 LINQ 之类的东西,因为它创建的查询对象是堆对象,它经常需要的委托也是如此。请改用简单的循环。
  • 如果您在绘制/更新中分配自己的引用类型,则必须尽可能转换为使用值类型或添加对象池。
  • 创建string对象是内存分配的另一个常见来源——相反,您可以重用 aStringBuilder并直接渲染它。
  • 将事物(尤其是:数字)转换为字符串,即使 forStringBuilder也会分配内存。您需要编写/找到无需分配的替代方案。我对这个类似问题的回答是针对int.

诊断内存分配位置的最佳方法是在 Windows 上使用CLR Profiler运行游戏。这将告诉您分配内存的位置和时间。只需优化,直到您不分配。

(或者直到您可靠地为每个级别/地图/房间/任何东西分配少于 1MB 的空间,并在适合卡顿的时间执行手动 GC - 例如静态加载屏幕或淡入淡出。)

代码 4 是未处理的异常。您需要安装一个输出消息的顶级异常处理程序,或者在调试器中运行您的游戏,以确定原因。

最后:这可能是纹理的压缩大小(使用 PNG 或 JPEG 或类似的)。如果您的纹理未压缩,则4096 × 4096 × 6 × 4 字节 = 384MB。这是巨大的——难怪你的内存用完了。您可以使用 DXT1 压缩它们并将它们缩小 6 倍(说明wiki)。你也可以降低他们的分辨率。你需要底面吗?

于 2012-08-12T13:19:13.597 回答