Java临时迭代器正在减慢我的Android游戏速度

时间:2012-07-15 07:25:47

标签: java android performance memory-management

由于性能原因,这个问题涉及Java中的内存管理:因为我正在开发这个程序作为Android游戏而内存GC会破坏我的性能。所以到目前为止我做了大量的工作,结果发现我在优化游戏的内存使用方面做得很好,但我有一个问题:迭代器!

这是我正在做的事情:

  1. 开始游戏关卡。
  2. 启动分配跟踪器(这样我们就会忽略在级别运行时将保留的所有分配;我有许多对象只能在级别的开头创建一次并且它们不是问题。)< / LI>
  3. 在关卡中做一些事情并获得分配。
  4. 我的分配充满了这个:

      

    466 24 java.util.AbstractList $ SimpleListIterator 12 java.util.AbstractList iterator
      465 24 java.util.AbstractList $ SimpleListIterator 12 java.util.AbstractList迭代器
      464 24 java.util.AbstractList $ SimpleListIterator 12 java.util.AbstractList迭代器
      463 24 java.util.AbstractList $ SimpleListIterator 12 java.util.AbstractList迭代器
      461 24 java.util.AbstractList $ SimpleListIterator 12 java.util.AbstractList迭代器
      456 24 java.util.ArrayList $ ArrayListIterator 12 java.util.ArrayList迭代器
      454 24 java.util.ArrayList $ ArrayListIterator 12 java.util.ArrayList迭代器
      453 24 java.util.ArrayList $ ArrayListIterator 12 java.util.ArrayList迭代器
      452 24 java.util.ArrayList $ ArrayListIterator 12 java.util.ArrayList iterator

    因此,在游戏运行时分配的唯一对象是迭代器!好吧,现在好了修复它......我问的是什么代码导致问题......这里是:

    for (Segment side : listOfSides.getSides()) {
        // do stuff
    }
    

    是的,事实证明for-each语法在幕后调用迭代器来填充每个元素。这完全合情合理,正是我的预期,但我没有意识到它可能会如此可怕地构建并导致游戏性能问题。如果我可以摆脱这个问题那么它真的会使我的游戏像闪电一样运行,无论它是什么手机。所以我的问题是:你会做什么来使所有这些临时迭代器都没有被创建然后立即丢弃导致令人讨厌的GC运行?这样做的奖励点不会让我的代码变得丑陋! (在Android上使用ndk不是一个选项)

    P.S。我想,对于我的所有ArrayLists,我可以开始使用get(int i)函数,因为它们是幕后的数组,我将用于索引的整数将放在堆栈而不是堆上。但是对于像HashMap和LinkedList这样的其他对象,我不知道该怎么做。

3 个答案:

答案 0 :(得分:14)

使用ArrayList和LinkedList可以使用get(int i)遍历元素(注意它对于LinkedList来说可能很慢,我不知道如何实现get()。)这是避免分配迭代器的推荐方法。如果您查看平台的源代码,您会注意到我们尽量避免使用for-each语法。

对于HashMap,您可以使用entrySet()获取基础集,然后调用toArray(Object [])并传递一个足够大的预分配数组来保存所有值。或者,看看你是否可以使用Android提供的各种SparseArray类。

答案 1 :(得分:1)

考虑到您已经放置的限制,唯一的解决方案是使用索引以及ArrayList或数组。对于LinkedListHashMap,我不认为有一种实用的替代方法可以避免任何分配。

但GC 真的这么慢,你真的需要像这样进行微优化的极端吗?

答案 2 :(得分:0)

当您将其与列表一起使用时,foreach循环始终会获取迭代器。只有两种方法可以使它不分配内存;两者都涉及到你的代码:

  • 在原始数组而不是List(最简单的方法)上使用它。

  • 在列表或其他Iterable上使用它,其iterator()函数不分配内存。这有点硬核,可能不值得,但我已经在我真正想要优化循环的情况下做到了。我是这样做的:

    1. 创建自己的实现Iterable的容器类。 (foreach循环将对任何实现Iterable的东西起作用,即使它不是List的子类。)
    2. 使该类在通过iterator()函数返回迭代器时不会分配内存。您可以通过拥有一个迭代器池,抓取一个并重置其值来实现此目的。你可能想要一个池而不是只重用一个池,因为你的一些代码可能有多个嵌套循环遍历同一个集合。
    3. 花几个小时调试上面丑陋的解决方案。总而言之,在大多数情况下都不值得。