2015-09-24 71 views
4

我有一个ArrayList,里面填充了150万个某些类的对象。当我通过使用Collection.sort方法对此列表进行排序时,JVM的分配内存会急剧增加。java的内存消耗Collection.sort()

所以我的问题是:

这是正常的吗?这可能是什么原因?这是垃圾收集器工作太慢还是不经常启动的问题?列表中的对象是否必须满足某些规范,以便在排序时消耗更少的内存(除了不包含那么多的数据)?

THX!

+0

您可能需要考虑quicksort或heapsort或另一种通常比TIMSort更快的内存有效排序。 –

+0

Java 8或更旧的Java版本? – Seelenvirtuose

+0

您的班级是否实施“Comparable”或者您是否使用自定义的“Comparator”? “compareTo”实现是什么样的? –

回答

4

为了排序Listdefault sorting implementation首先创建要排序的所有元素的数组副本。这会导致您在排序时观察到额外的堆消耗。这种复制是必要的,因为通用的排序算法不知道列表的结构,例如,如果它是随机访问的。

对于Java 8,sorting implementation was however changed将被委派给List的每个实现。这使用默认方法成为可能。对于ArrayList,通过实现更高效的排序算法,这个额外开销could be removed。因此,升级到Java 8很可能会解决您的问题。

垃圾收集对于您的问题没有任何问题。不幸的是,大型阵列很难处理,因为它们可能不适合年轻一代,最终可能会引发全面收集。

此外,正如评论中提到的,实际的排序是performed via Tim Sort since Java 7Arrays::sort实现。 Tim排序需要额外的堆空间。从javadoc:

临时存储要求从几乎排序的 输入数组的小常量到随机排序输入数组的n/2个对象引用有所不同。

如果这并不适用于你的使用情况,您可以通过系统属性java.util.Arrays.useLegacyMergeSort设置为true切换回先前的合并排序的实现。

毕竟,蒂姆排序然而仍然比合并排序更有效,因为合并排序需要另一个完整的数组副本。

+2

这个。这加上_“临时存储要求从几乎排序的输入数组的一个小常量到随机排序的输入数组的n/2个对象引用不同。”_这是Timsort对所有当前工作的sort()方法的实现说明 - 原始数据。 –