我正在Android中编写一个有点复杂的游戏引擎。
目前我有一个用于更新子系统的线程。
更新方法内部是更新游戏逻辑的方法,该方法基于当前游戏状态。
游戏状态有一个更新的场景。场景由根节点组成,它构成了一个简单的场景图结构。
根是具有子节点的节点,这些子节点也会更新,依旧等等。
无论如何,这一切都很好,花花公子并且效果很好,直到我在我的Logcat中得到一百万这些:03-29 09:23:22.866:D / dalvikvm(18554):GC_CONCURRENT释放了511K,52%免费2773K / 5767K,外部77K / 587K,暂停2ms + 3ms
我已将泄漏的原因隔离为更新循环,因为当我注释掉我更新子系统的方法时,没有GC消息。此外,我深入评论了更新循环,直到根节点的子节点更新是GC疯狂运行的点。
(GameLgoic)
public void onUpdate(float deltaTime)
{
if (gameState != null)
gameState.onUpdate(deltaTime);
}
(GameState)
public void onUpdate(float deltaTime)
{
scene.onUpdate(deltaTime);
}
(Scene)
public void onUpdate(float deltaTime)
{
root.onUpdate(deltaTime);
}
(SceneNode)
public void onUpdate(float deltaTime)
{
for (int i = 0; i < children.size(); ++i)
{
children.get(i).onUpdate(deltaTime); // Memory leak runs crazily here
}
}
如果我注释掉children.get(i).onUpdate(deltaTime)没有泄漏!我的思绪如此令人难以置信。谢谢你们。
答案 0 :(得分:2)
当我为Android制作游戏时,我遇到了类似的问题。摆脱这种情况的唯一方法是编写嵌入式C风格。 因此,如果你想要一个循环,尽可能重用你的计数变量以及你的边界变量,如下所示:
int i;
int max
void loop(){
max = bla.size();
for(i=0; i<max; i++){ ... }
}
对于你接触的其他所有内容,情况也是如此。因此,您可能会考虑保留对不再需要的对象的引用,并在以后回收它们。
它对我实施这些变化的游戏有何不同。帧率加倍,大幅减少滞后等等。
您应该查看DDMS工具,它是eclipse Android SDK的delieverd。您可以使用它来追踪分配,以避免这些问题。
另外,您应该考虑删除所有处理程序,因为每次进入循环并且无法回收时都会分配它们。因此,最好手动循环并多次遍历列表(循环中为get(x)
),而不是长期等待垃圾收集器。
答案 1 :(得分:0)
首先澄清术语 - 您不拥有a memory leak。当应用程序的内存使用量增长和增长时,会发生内存泄漏,因为它不会释放不再使用的内存。你有相反的问题 - 你发布了许多未使用的内存,必须是garbage collected。
释放未使用的内存通常是件好事;当清理已释放的内存所需的垃圾收集导致性能问题时,它只会成为一个问题,这就是你在这里看到的。
到目前为止,您发布的代码没有任何重大错误。问题似乎在于onUpdate()
方法,因此您可以发布代码。
通常,您可以通过尽可能重用对象来减少垃圾收集,而不是销毁和创建它们。
最后,一个小问题,你可以替换:
for (int i = 0; i < children.size(); ++i)
{
children.get(i).onUpdate(deltaTime); // Memory leak runs crazily here
}
for (SomeClass child : children) {
child.onUpdate(deltaTime);
}