由于性能原因,这个问题涉及Java中的内存管理:因为我正在开发这个程序作为Android游戏而内存GC会破坏我的性能。所以到目前为止我做了大量的工作,结果发现我在优化游戏的内存使用方面做得很好,但我有一个问题:迭代器!
这是我正在做的事情:
我的分配充满了这个:
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这样的其他对象,我不知道该怎么做。
答案 0 :(得分:14)
使用ArrayList和LinkedList可以使用get(int i)遍历元素(注意它对于LinkedList来说可能很慢,我不知道如何实现get()。)这是避免分配迭代器的推荐方法。如果您查看平台的源代码,您会注意到我们尽量避免使用for-each语法。
对于HashMap,您可以使用entrySet()获取基础集,然后调用toArray(Object [])并传递一个足够大的预分配数组来保存所有值。或者,看看你是否可以使用Android提供的各种SparseArray类。
答案 1 :(得分:1)
考虑到您已经放置的限制,唯一的解决方案是使用索引以及ArrayList
或数组。对于LinkedList
和HashMap
,我不认为有一种实用的替代方法可以避免任何分配。
但GC 真的这么慢,你真的需要像这样进行微优化的极端吗?
答案 2 :(得分:0)
当您将其与列表一起使用时,foreach循环始终会获取迭代器。只有两种方法可以使它不分配内存;两者都涉及到你的代码:
在原始数组而不是List(最简单的方法)上使用它。
在列表或其他Iterable上使用它,其iterator()函数不分配内存。这有点硬核,可能不值得,但我已经在我真正想要优化循环的情况下做到了。我是这样做的: