Bri*_*ian 63 java performance android garbage-collection
我正在使用Java平台为Android平台调整交互式游戏.偶尔会有绘图和交互进行垃圾收集的打嗝.通常它不到十分之一秒,但有时在非常慢的设备上可能会达到200毫秒.
我正在使用ddms profiler(Android SDK的一部分)来搜索我的内存分配来自哪里,并从我的内部绘图和逻辑循环中删除它们.
最糟糕的罪犯是短循环,如,
for(GameObject gob : interactiveObjects)
gob.onDraw(canvas);
Run Code Online (Sandbox Code Playgroud)
每次循环执行的地方都有iterator分配.我现在正在ArrayList为我的对象使用arrays().如果我想在内部循环中使用树或哈希,我知道我需要小心甚至重新实现它们而不是使用Java Collections框架,因为我无法负担额外的垃圾收集.当我在查看优先级队列时,可能会出现这种情况.
我也很难在哪里显示分数和进度Canvas.drawText.这是不好的,
canvas.drawText("Your score is: " + Score.points, x, y, paint);
Run Code Online (Sandbox Code Playgroud)
因为Strings,char数组StringBuffers将被分配到所有地方以使其工作.如果你有几个文本显示项目,并运行框架每秒60次开始加起来,将增加你的垃圾收集打嗝.我认为这里最好的选择是保持char[]数组并解码int或double手动解码并将字符串连接到开头和结尾.我想听听是否有更清洁的东西.
我知道必须有其他人来处理这件事.您如何处理它以及您发现在Java或Android上以交互方式运行的陷阱和最佳实践?这些gc问题足以让我错过手动内存管理,但不是很多.
Syn*_*r0r 56
我对Java的手机游戏合作......以避免GC'ing对象(这反过来,最好的办法应在一个点触发GC或其他和必杀死你的游戏的perfs)仅仅是为了避免在主游戏创建它们循环首先.
没有"干净"的方式来解决这个问题,我首先举一个例子......
通常情况下,你会在(50,25),(70,32),(16,18),(98,73)屏幕上看到4个球.好吧,这是你的抽象(为了这个例子简化):
n = 4;
int[] { 50, 25, 70, 32, 16, 18, 98, 73 }
Run Code Online (Sandbox Code Playgroud)
你"弹出"消失的第二个球,你的int []变成:
n = 3
int[] { 50, 25, 98, 73, 16, 18, 98, 73 }
Run Code Online (Sandbox Code Playgroud)
(注意我们甚至不关心"清理"第4球(98,73),我们只是跟踪我们剩下的球数).
遗憾的是,手动跟踪物体.这是如何在大多数当前在移动设备上运行良好的Java游戏上完成的.
现在是字符串,这是我要做的:
BufferedImage[10]数组中的数字0到9 .BufferedImageBufferedImage[10]你预先存储它们的位置每次复制相应的数字(0到9).这给你两全其美:你得到了drawtext(...)字体的重用,你在主循环中创建了完全零对象(因为你也躲过了对drawtext(...)的调用,这本身可能很好疯狂地产生,好,不必要的垃圾).
这种"零对象创建绘制分数"的另一个"好处" 是对字体进行仔细的图像缓存和重用并不是真正的"手动对象分配/释放",它实际上只是小心缓存.
它不是"干净",它不是"好习惯",而是它在顶级手机游戏中的表现(比如说,Uniwar).
它很快.快点快.比任何涉及对象创建的速度都快.
PS:其实如果你仔细看几个手机游戏,你会发现通常字体实际上不是系统/ Java字体,而是专门为每个游戏制作的像素完美字体(这里我只给你一个如何缓存系统的例子)/Java字体,但显然你也可以缓存/重用像素完美/位图字体).
Eon*_*nil 15
虽然这是一个2岁的问题......
避免GC滞后的唯一且最好的方法是通过静态地(包括在启动时)分配所有必需对象来避免GC本身.预先创建所有必需的对象,永远不要删除它们.使用对象池重用现有对象.
无论如何,即使您对代码进行了所有可能的优化,也可能会暂停.因为除了你的应用程序代码以外的任何东西仍在内部创建GC对象,最终会变成垃圾.例如,Java基础库.即使使用简单的List类也可能会产生垃圾.(因此应该避免)调用任何Java API都可能会产生垃圾.当你使用Java时,这些分配是不可避免的.
此外,由于Java旨在利用GC,如果您真的试图避免使用GC,则会因缺少功能而遇到麻烦.(甚至List应该避免类)因为它允许 GC,所有库都可以使用GC,所以你几乎/几乎没有库.我认为在基于GC的语言上避免使用GC是一种疯狂的试验.
最终,唯一可行的方法是降低到可以完全控制记忆的水平.如C族语言(C,C++等).所以去NDK吧.
注意
现在谷歌正在发布增量(并发?)GC,可以减少很多停顿.无论如何,增量GC意味着随着时间的推移只分配GC负载,因此如果分配不理想,您仍然会看到最终的暂停.由于较少的批处理和分配操作开销的副作用,GC性能本身也将降低.
我建立了自己的无垃圾版本String.format,至少是一种.你在这里找到它:http://pastebin.com/s6ZKa3mJ(请原谅德国评论).
像这样使用它:
GFStringBuilder.format("Your score is: % and your name is %").eat(score).eat(name).result
Run Code Online (Sandbox Code Playgroud)
一切都写成一个char[]数组.我必须手动(逐个数字)实现从整数到字符串的转换,以摆脱所有垃圾.
除此之外,我用SparseArray在可能的情况,因为所有的Java数据结构等HashMap,ArrayList等有为了应对原始类型使用拳.每次装箱int时Integer,Integer都必须通过GC清理此物体.