非运行时分配解决方案 - ArrayList

时间:2010-12-07 21:54:21

标签: java android allocation

我正在用Java制作游戏。我需要一些针对当前运行时分配的解决方案,由我的ArrayList引起。垃圾收集器每隔一分钟或30秒开始运行,因为我正在通过此集合调用draw和updates方法。

我应该如何进行非运行时分配解决方案?

提前致谢,如果需要,我的代码会在我的Manager类中发布,其中包含ArrayList个对象。

一些代码:

@Override
public void draw(GL10 gl) {
  final int size = objects.size();
  for(int x = 0; x < size; x++) {
    Object object = objects.get(x);
    object.draw(gl);
  }
}

public void add(Object parent) {
  objects.add(parent);
}

     //Get collection, and later we call the draw function from these objects
public ArrayList<Object> getObjects() {
   return objects;
}

public int getNumberOfObjects() {
   return objects.size();
}

更多解释:我与此混合的原因是因为(1)我发现ArrayList实现速度慢并导致滞后,(2)我想合并对象/组件在一起。从我的Thread类中触发更新调用时,它会遍历我的集合,使用Manager的更新功能在树/图中向下发送。

查看一个开源项目Replica Island时,我发现他使用了另一个类FixedSizeArray,他自己编写了这个类。由于我不擅长Java,我想让事情变得更容易,现在我正在寻找另一种解决方案。最后,他解释了为什么他成了特殊班级:

  

FixedSizeArray是ArrayList等标准Java集合的替代品。它旨在提供一个固定长度的连续数组,无需需要任何运行时分配即可访问,排序和搜索。此实现区分了数组的“容量”(它可以包含的最大对象数)和数组的“count”(插入到数组中的当前对象数)。诸如set()和remove()之类的操作只能对已明确添加() - 对数组的对象进行操作;也就是说,大于getCount()但小于getCapacity()的索引不能单独使用。

4 个答案:

答案 0 :(得分:4)

  

我看到ArrayList实现很慢并导致滞后......

如果你看到这一点,你就会误解证据并跳到不合理的结论。 ArrayList并不慢,并且它不会导致滞后......除非你以特别次优的方式使用该类。

数组列表分配内存的唯一时间是创建列表,添加更多元素,复制列表或调用iterator()

  • 创建数组列表时,会创建2个java对象;一个用于ArrayList,另一个用于其后备阵列。如果使用initialCapacity参数并给出适当的值,则可以安排后续更新不会分配内存。

  • 添加或插入元素时,数组列表可能分配一个新对象。但这只发生在后备阵列太小而无法容纳所有元素的情况下,并且当它确实发生时,新的后备阵列通常旧的后缀阵列的两倍。因此,插入N个元素将导致最多 log2(N)分配。此外,如果您使用适当的initialCapacity创建数组列表,则可以保证在添加或插入时有分配。

  • 将列表复制到另一个列表或数组时(使用toArray或复制构造函数),您将获得1或2个分配。

  • iterator()方法每次调用时都会创建一个新对象。但是你可以通过使用显式索引变量List.size()List.get(int)进行迭代来避免这种情况。 (请注意for (E e : someList) { ... }隐式调用List.iterator()。)

(像Collections.sort这样的外部操作需要额外的分配,但这不是数组列表的错误。任何列表类型都会发生。)

简而言之,使用数组列表获得大量分配的唯一方法是创建大量数组列表,或者非智能地使用它们。

你发现的FixedSizedArray课听起来像是浪费时间。听起来这相当于创建一个具有初始容量的ArrayList ...如果初始容量错误,它将中断的限制。编写它的人可能不太了解Java集合。

答案 1 :(得分:2)

目前还不太清楚你在问什么,但是:

如果您在编译时知道集合中应该包含哪些对象,请将其设置为数组而不是ArrayList,并将内容设置为初始化块。

Object[] objects = new Object[]{obj1,obj2,obj3};

答案 2 :(得分:1)

是什么让您认为您知道GC正在回收什么?你有没有想过你的申请?

答案 3 :(得分:1)

“非运行时分配”是什么意思?我真的不确定你在这种情况下的“分配”是什么意思......内存的分配?那显然是在运行时完成的。你显然不是指在编译时已知的任何类型的固定对象池,因为你的代码允许以几种不同的方式向列表添加对象(而不是你能够在编译时为它们分配任何东西)即使你是)。

除此之外,您发布的代码中没有任何内容会单独导致垃圾收集。当程序中的任何内容都没有对它们进行强引用时,对象只能被垃圾收集,而您发布的代码只允许向ArrayList添加对象(尽管可以通过调用getObjects()删除它们并从中删除它们, 当然)。只要您不从objects列表中删除对象,就不会重新分配objects指向不同的列表,并且包含它的对象本身不符合垃圾回收的条件,它包含的任何对象都不可用于垃圾收集。

所以基本上,你发布的代码没有任何具体问题,你问的问题也没有意义。也许您可以提供更多详细信息,或者更好地解释您的问题究竟是什么以及您想要什么。如果是这样,请尝试将其添加到您的问题中。

修改

FixedSizeArray的描述和我在其中看到的代码,它看起来很大程度上等同于使用特定数组容量初始化的ArrayList(使用带{{1}的构造函数除了它会在运行时失败,如果有些东西试图在它的数组已满时添加它,int initialCapcacity将扩展自己以保持更多并继续正常工作。说实话,它似乎是一个毫无意义的类,可能是因为作者实际上并不理解ArrayList而写的。

另请注意,其关于“不需要任何运行时分配”的声明有点误导......它当然必须在创​​建时分配一个数组,但它只是拒绝分配一个新数组,如果它的初始数组填上。您可以使用ArrayList完成相同的操作,只需给它一个ArrayList,该initialCapacity至少足以容纳您将添加到其中的最大对象数。如果你这样做,并且事实上确保你永远不会向它添加超过该数量的对象,它将永远不会在创建后分配新数组。

但是,这些都与您提出的有关垃圾收集的问题没有任何关系,并且您的代码仍然没有显示任何会导致大量对象被垃圾回收的内容。如果存在任何问题,则可能与实际调用addgetObjects方法的代码及其正在执行的操作有关。