如何避免 Java 游戏中的垃圾收集延迟? (最佳实践)[关闭]

2023-11-23

我正在为 Android 平台调整 Java 交互游戏的性能。有时,垃圾收集的绘图和交互会出现问题。通常它不到十分之一秒,但有时在非常慢的设备上可能会长达 200 毫秒。

我正在使用 ddms 分析器(Android SDK 的一部分)来搜索我的内存分配来自哪里,并将它们从我的内部绘图和逻辑循环中删除。

最严重的罪犯是短循环,例如,

for(GameObject gob : interactiveObjects)
    gob.onDraw(canvas);

每次执行循环时都会有一个iterator分配。我正在使用数组(ArrayList)现在为我的对象。如果我想要在内循环中使用树或哈希,我知道我需要小心,甚至重新实现它们,而不是使用 Java 集合框架,因为我负担不起额外的垃圾收集。当我查看优先级队列时可能会出现这种情况。

我在想要使用以下方式显示分数和进度时也遇到了麻烦Canvas.drawText。这不好,

canvas.drawText("Your score is: " + Score.points, x, y, paint);

because Strings, char数组和StringBuffers将被分配到所有地方以使其发挥作用。如果您有一些文本显示项目,并且每秒运行该框架 60 次,那么该帧就会开始累积,并会增加垃圾收集的问题。我认为最好的选择是保留char[]数组并解码你的int or double手动进入其中并将字符串连接到开头和结尾。我想听听是否有更干净的东西。

我知道肯定还有其他人在处理这个问题。您如何处理它?您发现在 Java 或 Android 上交互式运行有哪些陷阱和最佳实践?这些 gc 问题足以让我怀念手动内存管理,但不是很多。


我曾开发过 Java 手机游戏……避免 GC 对象的最佳方法(反过来shall在某一点或另一点触发 GC,并且shall杀死你的游戏的性能)只是为了避免首先在你的主游戏循环中创建它们。

没有“干净”的方法来处理这个问题,我首先举一个例子......

通常,屏幕上有 4 个球,分别位于 (50,25)、(70,32)、(16,18)、(98,73)。好吧,这是你的抽象(为了这个例子而简化):

n = 4;
int[] { 50, 25, 70, 32, 16, 18, 98, 73 }

你“弹出”第二个球消失了,你的 int[] 变成:

n = 3
int[] { 50, 25, 98, 73, 16, 18, 98, 73 }

(注意我们甚至不关心“清理”第四个球(98,73),我们只是记录剩下的球数)。

遗憾的是,手动跟踪物体。这就是当前在移动设备上运行的大多数表现良好的 Java 游戏的实现方式。

现在对于字符串,我会这样做:

  • 在游戏初始化时,使用预绘制绘制文本(...) 只有一次您保存在 a 中的数字 0 到 9BufferedImage[10] array.
  • 游戏初始化时,预绘制一次“你的分数是: ”
  • if the “你的分数是: ”确实需要重新绘制(因为,比如说,它是透明的),然后从预存储中重新绘制它BufferedImage
  • 循环计算分数的数字并在“你的分数是: ”,手动将每个数字一一对应(通过每次从您的计算机中复制相应的数字(0 到 9))BufferedImage[10]您预先存储它们的位置。

这为您提供了两全其美的效果:您可以重用绘制文本(...)font 并且您在主循环期间创建了零个对象(因为您also回避了呼叫绘制文本(...)其本身may很可能会蹩脚地产生,好吧,不必要的废话)。

这样做的另一个“好处”“零物体创建平局得分”仔细的图像缓存和字体重用并不是真的“手动对象分配/释放”,这实际上只是仔细的缓存。

这不是“干净”,也不是“良好实践”,但这就是顶级手机游戏(比如 Uniwar)的做法。

而且速度很快。真快。比...快anything涉及对象的创建。

P.S:其实如果你仔细看一些手机游戏,你会发现很多时候字体实际上不是系统/Java字体,而是专门为每个游戏制作的像素完美字体(这里我只是给你举了一个如何缓存系统字体的例子) /Java 字体,但显然您也可以缓存/重用像素完美/位图字体)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何避免 Java 游戏中的垃圾收集延迟? (最佳实践)[关闭] 的相关文章

随机推荐