当前位置: 首页 > 面试题库 >

如何避免Java游戏中垃圾回收的延迟?(最佳做法)

牟子真
2023-03-14
问题内容

我正在针对Java平台在Java中优化交互式游戏的性能。有时会在绘图和交互方面进行垃圾收集工作。通常小于一秒的十分之一,但有时在非常慢的设备上可能长达200毫秒。

我正在使用ddms事件探查器(Android SDK的一部分)来搜索我的内存分配来自何处,并从内部绘图和逻辑循环中删除它们。

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

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

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

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

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

因为Stringschar数组和StringBuffers将全部分配以使其工作。如果您有几个文本显示项目,并且每秒运行60次框架,这将开始累加,这会增加垃圾收集的麻烦。我认为最好的选择是保留char[]数组并解码intdouble手动将其解码,然后将字符串连接到开头和结尾。我想听听是否有清洁剂。

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


问题答案:

我对Java的手机游戏合作......以避免GC’ing对象(这反过来,最好的办法 在一个点触发GC或其他和
杀死你的游戏的perfs)仅仅是为了避免在主游戏创建它们首先循环。

没有“干净”的方法可以解决这个问题,我先举一个例子。

通常,您在屏幕上有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游戏中完成的。

现在,对于字符串,这是我要做的:

  • 在游戏初始化时, 仅在 将数字0到9保存在数组中之后 使用 drawText(…)进行 预绘制。 __BufferedImage[10]
  • 在游戏初始化时,预先绘制一次 “您的分数是:”
  • 如果 “您的分数是:” 确实需要重绘(因为它是透明的),则从您的预存中重绘BufferedImage
  • 循环以计算分数的位数,并在 “您的分数为:”之后 ,将每个数字手动一个接一个地添加(每次从您BufferedImage[10]预先存储的位置复制对应的数字(0到9))。

这让您 两全其美 :您可以重用 drawtext(…) 字体,并且在主循环中创建了完全为零的对象(因为您 回避了对
drawtext(…) 的调用,这本身很 可能 是糟糕地产生不必要的废话)。

这个 “零对象创建绘图分数”的 另一个“好处” 是,仔细的图像缓存和字体的重用并不是真正的 “手动对象分配/重新分配” ,而是真正的仔细缓存。

这不是“干净的”,也不是“好的做法”,但这是在一流的手机游戏(例如Uniwar)中的实现方式。

而且速度很快。快点 比涉及对象创建的 任何事物 都要快。

PS:实际上,如果您仔细看一些手机游戏,您会发现字体实际上不是系统/
Java字体,而是专门为每个游戏制作的像素完美字体(在这里,我仅向您提供了有关如何缓存系统的示例/
Java字体,但显然您也可以缓存/重复使用像素完美/位图字体)。



 类似资料:
  • 主要内容:1 什么是Java 垃圾回收,2 Java 垃圾回收的优势,3 如何取消对象引用,4 finalize()方法,5 gc()方法,6 Java 垃圾回收的例子1 什么是Java 垃圾回收 在Java中,垃圾意味着未引用的对象。 垃圾回收是自动回收运行时未使用的内存的过程。换句话说,这是销毁未使用对象的一种方法。 我们在C语言中使用free() 函数,在C ++中使用delete()。但是,在Java中它是自动执行的。因此,java提供了更好的内存管理。 2 Java 垃圾回收的优势 它

  • 问题内容: 我想知道Java中发生的垃圾回收。它真的能够处理所有未使用的对象并释放最大可能的内存吗? 我还想知道Java垃圾收集与另一种语言(例如C#)相比如何?然后,如何自动垃圾收集与从像C这样的语言中进行手动收集相比又能达到更好的效果呢? 问题答案: 是的,这就是垃圾收集的重点。 有许多不同形式的垃圾收集。如果不增强算法,最简单的形式即引用计数就无法处理某些类型的垃圾(循环引用)。 Java(

  • 问题内容: 我正在寻找有关如何在低延迟至关重要的环境中最大程度地调整年轻一代(相对于老一代)的争论。 我自己的测试倾向于表明,当年轻一代相当大时(例如-XX:NewRatio <3),延迟是最低的,但是我不能直觉地认为年轻一代越大,进行垃圾处理的时间就越多收集。 该应用程序在Linux 64位jdk 6上运行。 内存使用量大约是启动时加载的50万兆个长寿命对象(=数据缓存),并且从那里仅创建(很多

  • 问题内容: 有时您可能想要避免/最小化垃圾收集器,因此我想确定如何做。 我认为下一个是正确的: 在函数的开头声明变量。 使用数组而不是切片。 还有吗 问题答案: 避免垃圾相对简单。您需要了解在哪里进行分配,并查看是否可以避免分配。 首先,在函数开头声明变量将无济于事。编译器不知道区别。但是,人类会知道其中的区别,并且会惹恼他们。 使用数组而不是切片将是可行的,但这是因为将数组(除非取消引用)放置在

  • 问题内容: 即使很棘手,也可以在Java中强制进行垃圾回收吗?我知道;,;但是他们只建议做GC。我该如何强制GC? 问题答案: 最好的选择是调用,这只是向垃圾收集器提示你要它进行收集。由于垃圾收集器是不确定的,因此无法强制立即收集。

  • 垃圾回收 我们对生产中花了很多时间来调整垃圾回收。垃圾回收的关注点与Java大致相似,尽管一些惯用的Scala代码比起惯用的Java代码会容易产生更多(短暂的)垃圾——函数式风格的副产品。Hotspot的分代垃圾收集通常使这不成问题,因为短暂的(short-lived)垃圾在大多情形下会被有效的释放掉。 在谈GC调优话题前,先看看这个Attila的报告,它阐述了我们在GC方面的一些经验。 Scal