【问题标题】:Non runtime allocation solution - ArrayList非运行时分配解决方案——ArrayList
【发布时间】:2010-12-07 21:54:20
【问题描述】:

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

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

提前致谢,如果需要,我的代码从我的 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 类触发更新调用时,它会通过我的集合,使用管理器的更新功能将内容发送到树/图。

查看一个开源项目 Replica Island 时,我发现他使用了他自己编写的替代类 FixedSizeArray。由于我不太擅长 Java,所以我想让事情变得更简单,现在我正在寻找另一种解决方案。最后,他解释了他为什么要参加特殊课程:

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

【问题讨论】:

  • 垃圾收集器会运行很多。您完全无法控制它何时运行。你需要考虑到这一点。
  • 是的,但是因为我已经阅读过这个主题,所以可以让它经常不触发。
  • 你有多少个对象?
  • @Petro:目前,三个。但在开发过程中,这些将增加到大约 20 - 30 个。
  • 只是好奇,你为什么要查询'mObjects'的大小,然后再使用'objects'。

标签: java android allocation


【解决方案1】:

我看到 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 集合。

【讨论】:

  • 谢谢,我找到了问题。那是我根据里面有多少对象来遍历我的 ArrayList。因此,如果我有 3 个对象,我会调用 draw 方法 9 次,这就是问题所在。谢谢。
【解决方案2】:

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

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

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

【讨论】:

  • 嗯,这是个好主意,我现在可以实现它。但就灵活性而言,这并不是我想要的,因为在游戏过程中事情会通过这个集合进进出出。
  • +1 通常我也建议首选 ArrayLists,但在游戏编程中它们可以在性能方面产生巨大的差异。
  • 嗯,这证明了我对 ArrayList 的怀疑。
  • 无论这里有什么问题,我认为这与使用 ArrayList 而不是数组有关。
【解决方案3】:

是什么让您认为您知道 GC 正在回收什么?您是否分析过您的应用程序?

【讨论】:

  • 好吧,更具体地说,我正在为 android 制作游戏,并使用 DDMS 工具进行了检查,在那里我可以看到 GC 何时运行。
  • DDMS 工具告诉你什么?
  • 这个:12-07 22:59:48.759: DEBUG/dalvikvm(579): GC_EXPLICIT freed 1246 objects / 59248 bytes in 66ms
  • 这并不意味着被释放的对象就是 ArrayList 中的对象。试试这个实验。注释掉所有绘图,然后重新运行 DDMS 工具,看看它说你 GC'ed。
  • 嗯,没错,但我怀疑是这种情况。但是,它是在我实现了这个 Manager 之后才出现的。
【解决方案4】:

“非运行时分配”是什么意思?在这种情况下,我什至不确定您所说的“分配”是什么意思……分配内存?显然,这是在运行时完成的。您显然也不是指在编译时已知的任何类型的固定对象池,因为您的代码允许以几种不同的方式将对象添加到列表中(并不是说您可以在编译时为它们分配任何东西即使你是)。

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

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

编辑:

FixedSizeArray 的描述和我查看的代码来看,它似乎在很大程度上等同于使用特定数组容量初始化的ArrayList(使用采用int initialCapcacity 的构造函数),除了它如果在其数组已满时尝试添加某些内容,则会在运行时失败,ArrayList 将自行扩展以容纳更多并继续正常工作。老实说,这似乎是一个毫无意义的课程,可能是因为作者没有真正理解ArrayList而写的。

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

但是,这与您所说的有关垃圾收集的问题没有任何关系,而且您的代码仍然没有显示任何会导致大量对象被垃圾收集的内容。如果有任何问题,可能与实际调用 addgetObjects 方法的代码及其所做的事情有关。

【讨论】:

  • 感谢您的回答。我在编辑后的问题中添加了更多信息。
  • 感谢您的解释。我确实为那个特定的 ArrayList 使用了最大数量的对象。我是否应该进一步扩展我的问题并展示我如何获取此集合以进行更新和绘图调用以查看它是否已优化或我是否能够优化它?
  • @Julian:可能,但我真的想知道这个问题是否与此有关。你是说你只在列表中添加了 3 个对象吗?如果问题是这个列表和这 3 个对象,我不知道你最终会如何得到 1246 个对象。
  • 是的,但是我自己用这个系统看屏幕的时候卡顿比较大,比如在线程类中调用对象本身的更新函数时没有看到。
猜你喜欢
  • 2012-05-08
  • 2023-03-06
  • 1970-01-01
  • 2023-04-09
  • 2022-07-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多