我正在针对Java平台在Java中优化交互式游戏的性能。有时会在绘图和交互方面进行垃圾收集工作。通常小于一秒的十分之一,但有时在非常慢的设备上可能长达200毫秒。
我正在使用ddms事件探查器(Android SDK的一部分)来搜索我的内存分配来自何处,并从内部绘图和逻辑循环中删除它们。
最严重的罪犯是短循环,例如
for(GameObject gob : interactiveObjects) gob.onDraw(canvas);
每次执行循环时,都会iterator分配一个。我现在ArrayList为我的对象使用数组()。如果我想在内部循环中使用树或哈希,我知道我需要小心甚至重新实现它们,而不是使用Java Collections框架,因为我负担不起额外的垃圾回收。当我查看优先级队列时,可能会出现这种情况。
iterator
ArrayList
我也想在显示分数和使用进度时遇到麻烦Canvas.drawText。这不好,
Canvas.drawText
canvas.drawText("Your score is: " + Score.points, x, y, paint);
因为Strings,char数组和StringBuffers将全部分配以使其工作。如果您有几个文本显示项目,并且每秒运行60次框架,这将开始累加,这会增加垃圾收集的麻烦。我认为最好的选择是保留char[]数组并解码int或double手动将其解码,然后将字符串连接到开头和结尾。我想听听是否有清洁剂。
Strings
char
StringBuffers
char[]
int
double
我知道那里肯定还有其他人在处理这个问题。您如何处理它,发现在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游戏中完成的。
现在,对于字符串,这是我要做的:
BufferedImage[10]
BufferedImage
这让您 两全其美 :您可以重用 drawtext(…) 字体,并且在主循环中创建了完全为零的对象(因为您 也 回避了对 drawtext(…) 的调用,这本身很 可能 是糟糕地产生不必要的废话)。
这个 “零对象创建绘图分数”的 另一个“好处” 是,仔细的图像缓存和字体的重用并不是真正的 “手动对象分配/重新分配” ,而是真正的仔细缓存。
这不是“干净的”,也不是“好的做法”,但这是在一流的手机游戏(例如Uniwar)中的实现方式。
而且速度很快。快点 比涉及对象创建的 任何事物 都要快。
PS:实际上,如果您仔细看一些手机游戏,您会发现字体实际上不是系统/ Java字体,而是专门为每个游戏制作的像素完美字体(在这里,我仅向您提供了有关如何缓存系统的示例/ Java字体,但显然您也可以缓存/重复使用像素完美/位图字体)。