使用托管语言(如C#)编写游戏时,典型的陷阱是什么?[关闭]


66

在使用诸如C#之类的托管语言为PC编写游戏时,遇到了什么陷阱?如何解决这些陷阱?


在Stack Overflow上最好问这个问题,因为关于游戏的问题很少。
克里斯·加勒特

31
@Chris:非常不同意:这个问题专门提到游戏!每隔16毫秒推送一次更新时遇到的问题与大多数桌面应用程序中遇到的问题完全不同。
安德鲁·罗素

这个问题还不清楚。Java和C#的差异足够大,仅适用于非常通用的建议。到目前为止,所有答案都是C#。此外,未提及目标平台-好的建议可能会因设备而异(例如,针对手机,zune,xbox的编程,与针对PC的编程不同)。甚至有人已经回答了一个广泛的问题,即托管语言本身就是“陷阱”。
paulecoyote

@paulecoyote:我改为仅询问有关C#的问题。另外,由于没有提到特定的平台,因此它与PC有关。
迈克尔·克莱门特

@Michael假设平台是一个危险的假设,因为它们在实现上有很大不同,因此特别要提及Windows并完全删除“ like”和“ Java”。
paulecoyote

Answers:


69

我对java不太了解,所以这是从.net开发人员的角度来看的。

迄今为止最大的垃圾是垃圾。Windows上的.net垃圾收集器做的很棒,您可以在没有宝宝坐大部分时间的情况下摆脱困境。在xbox / winPhone7上是另一回事。如果每隔几帧就会出现停顿,则垃圾收集可能会导致您遇到问题。目前,它每分配1mb就会触发一次。

这里是一些处理垃圾的技巧。您实际上不必担心其中的大多数,但是有一天它们可能会派上用场。

  • 将的内容绘制GC.GetTotalMemory()到屏幕上。这使您可以大致估算出游戏使用的已分配字节数。如果几乎不动,那您就没事了。如果上升速度很快,那么您就会遇到问题。
  • 尝试预先分配所有对象。如果您没有在游戏开始前分配所有内容,那么每次您遇到一大笔分配时,您都将陷入停滞。没有分配,没有收藏。就如此容易。
  • 加载后,调用GC.Collect()。如果您知道您的大部分大分配都被拒之门外,那么最好让系统知道。
  • 不要GC.Collect()每帧都打电话。保持垃圾和所有这些东西似乎是一个好主意,但请记住,唯一比垃圾收集更糟糕的是垃圾收集。
  • 查找您的垃圾来自何处。有一些常见的原因,例如连接字符串而不是使用StringBuilder(请注意,StringBuilder这不是魔术子弹,并且仍然可能导致分配!!这意味着简单的操作,例如在字符串末尾添加数字会产生大量垃圾)或使用foreach循环在使用该集合IEnumerable接口也可以在你自己知道创建垃圾(例如,foreach (EffectPass pass in effect.CurrentTechnique.Passes)是常见的一种)
  • 使用诸如CLR内存分析器之类的工具来确定内存的分配位置。关于如何使用此工具的教程很多。
  • 当您知道游戏过程中的分配位置时,请查看是否可以使用诸如合并对象之类的技巧来减少分配数量。
  • 如果所有其他方法均失败,请使您的集合运行得更快!紧凑框架上的GC会遵循您代码中的每个参考,以找出不再使用的对象。重构代码使用更少的引用!
  • 请记住IDisposable在包含非托管资源的类上使用。您可以使用它们清理GC无法释放的内存。

要考虑的另一件事是浮点性能。尽管.Net JITer进行了大量特定于处理器的优化,但它不能使用SSE或任何其他SIMD指令集来加快浮点数学运算的速度。这会导致C ++和C#游戏之间的速度差异很大。如果您使用Mono,则可以使用一些特殊的SIMD数学库。


完全同意。“较小”平台上的垃圾收集器实现似乎是完整的垃圾。
Krisc

好的帖子,但是关于您关于“预先分配堆对象”的声明,我建议阅读“关于值类型的真相
贾斯汀”,2010年

最重要的一点是,当您优化代码时,它确实值得您了解针对其进行优化的平台。那实际上不是关于值类型/引用类型的注释,任何长期存在的对象都不太可能出现在堆栈中。这实际上是要确保您在加载时完成尽可能多的分配,并且在游戏过程中不要碰到神奇的1mb障碍。xna面向aslo的所有.net实现都有一个整洁的保证,时间紧靠在一起分配的对象在空间上将接近,这对于perf可能是很好的。
Cubed2D 2010年

好像我也忘了提及xbox上的当前紧凑框架对内联方法调用敏感。不过,请为最糟糕的perf场景保留该选项,使用ref版本的maths方法看起来确实很丑陋!
Cubed2D 2010年

10

典型的性能陷阱是在游戏的设计/开发中不考虑垃圾收集器。产生过多的垃圾会导致游戏中出现“打h”,这会在GC运行相当长的时间时发生。

对于C#,使用值对象和“ using”语句可以减轻来自GC的压力。


3
另外,如果您刚刚完成了分配/空闲重循环,或者发现有空闲循环,则可以告诉垃圾回收器显式运行。
BarrettJ 2010年

16
using语句与垃圾回收无关!它用于IDisposable对象-用于释放非托管资源(即:那些未由垃圾收集器处理的资源)。
安德鲁·罗素

9

我想说我用C#编写游戏时遇到的最大问题是缺少像样的库。我发现的大多数端口都是直接端口,但不完整,或者是C ++库的包装器,因此封送处理会严重降低性能。(我专门针对OGRE库谈论MOgre和Axiom,而针对Bullet物理库谈论BulletSharp)

如果您对导致语言变慢的原因(封送处理,垃圾回收)有充分的了解,那么托管语言(与解释语言不同-Java和C#都不再进行解释了)可以和本地语言一样快。我认为真正的问题是图书馆开发人员尚未意识到这一点。


这是关于管理C#和Java而不是解释Java的一个好点……编辑了我的问题以使其更加准确:)
Michael Klement

2
一般而言,封送处理是性能瓶颈,但也有助于了解可绑定类型-可直接映射到非托管内存而不会对性能造成重大影响的类型。msdn.microsoft.com/en-us/library/75dwhxf7.aspx
肖恩·爱德华兹

8

就像其他人所说的那样,GC收集暂停是最大的问题。使用对象池是一种典型的解决方案。


4

不解释C#和Java。它们被编译为中间字节码,在JIT之后,该字节码变得与本地代码一样快(或几乎可以忽略不计)。

我发现最大的陷阱是释放直接影响用户体验的资源。这些语言不会像C ++那样自动支持确定性终结处理,如果您不希望这样做,则会导致诸如网格物体之类的东西在您认为被破坏后漂浮在场景中。(C#通过IDisposable完成确定性终结,我不确定Java会做什么。)

除此之外,托管语言实际上具有处理游戏所需性能的能力,远胜于他们所赞誉的语言。编写良好的托管代码要比编写不良的本机代码快得多。


是的,感谢您的注释,它已经纠正了解释/管理的问题;)此外,网格物体在场景中漂浮的好处是。在考虑GC问题时没有想到这一点
Michael Klement

1
IDisposable允许确定性清除时间紧迫且不受管理的资源,但不会直接影响终结处理或垃圾收集器。
山姆·哈威尔

4

Java和C#都不会被解释。它们都被编译成本机代码。

它们和游戏的最大问题是必须进行编码,以使它们在游戏过程中永远不会垃圾收集。您必须跳过的滚铁环的数量几乎超过了首先使用滚铁环的好处。在游戏编程中,必须避免使那些语言有趣的用于应用程序或服务器编程的大多数功能,否则在游戏进行和垃圾收集时,您会在游戏过程中长时间停顿。


至少在C#中,可以很好地处理垃圾回收,所以我不会说这是一个破坏交易的行为。通过适当的线程化和对程序状态的了解,可以避免性能问题。您仍然需要考虑另一件事,它确实使托管语言的托管程度有所降低。
Karantza 2010年

4
值得注意的是,在.NET 4中,垃圾收集器支持所有三代对象的后台收集。这应该有效地最小化游戏中垃圾收集对性能的影响。相关链接:geekswithblogs.net/sdorman/archive/2008/11/07/…–
Mike Strobel

垃圾收集器正在发展,正如Mike Strobel所指出的那样,一些垃圾收集器已经投入生产,几乎消除了这种陷阱。
山姆·哈威尔

2
C#和Java均未编译为本机代码。C#编译为MSIL,Java编译为字节码。垃圾回收不会产生任何“长时间”的停顿,但可能会造成“打ic”。
Cloudanger 2010年

2

通过使用此类语言(或使用诸如XNA,TorqueX引擎等工具)制作游戏时,我看到一个很大的陷阱,那就是很难找到一支拥有优秀专家的优秀团队,他们需要具备与之等效的游戏技能。在C ++和OpenGL / DirectX中找到人非常容易。

游戏开发行业仍然非常沉迷于C ++,因为用于推出大型或精打细算的小型游戏的大多数工具和管道都是用C ++编写的,据我所知,您可以使用所有官方开发工具包针对XBox,PS3和Wii的发行版仅与C ++兼容(现在XBox工具集可能会得到更多管理,有人知道吗?)

如果您现在想为游戏机开发游戏,您几乎可以在XBox上获得XNA和C#,然后仅在游戏库的一个名为XBox Live Indie Games的侧面部分获得。一些赢得比赛等的人会被选择将他们的游戏移植到真正的XBox Live Arcade。除此之外,还没有为PC制作游戏的计划。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.