当前位置: 首页 > 知识库问答 >
问题:

排序期间Java内存不足

欧浩淼
2023-03-14

我有一个关于使用数字列表构建金字塔的任务,但是有一个测试有一个问题。在我的任务中,我需要对列表进行排序。我使用Collections.sort():

Collections.sort(inputNumbers, (o1, o2) -> {
            if (o1 != null && o2 != null) {
                return o1.compareTo(o2);
            } else {
                throw new CannotBuildPyramidException("Unable to build a pyramid");
            }
        });

但此测试失败

@Test(expected = CannotBuildPyramidException.class)
    public void buildPyramid8() {
        // given
            List<Integer> input = Collections.nCopies(Integer.MAX_VALUE - 1, 0);

        // run
        int[][] pyramid = pyramidBuilder.buildPyramid(input);

        // assert (exception)
    }

使用内存错误而不是我自己的无法构建金字塔例外(排序后将以另一种方法抛出)。我知道这是因为蒂姆索特在收集.sort()方法。我试图使用堆排序,但我甚至无法交换元素,因为我的输入列表被初始化为 Arrays.asList(),当我使用 set() 方法时,我得到了不受支持的操作例外。然后我试图将我的列表转换为常见的数组列表

ArrayList<Integer> list = new ArrayList<>(inputNumbers);

但我再次出现OutOfMemoryError错误。不允许编辑测试。我不知道该怎么处理这个问题。我正在使用Java8和IntelliJIdea SDK

共有2个答案

巢睿
2023-03-14

这个列表太大了!Collections.nCopies(Integer.MAX_VALUE-1,0);给了我们2^31-1个元素的列表(2147483647),每个元素在内存中占用大约4个字节(这是整数的“简化”大小)。如果我们乘以它,我们将需要大约8.59 GB的内存来存储所有这些数字。你确定你有足够的内存来存储它吗?

我认为这个测试写得很糟糕——不应该试图创建这么大的< code >列表。

夏长卿
2023-03-14

请注意,由集合.nCopies(整数.MAX_VALUE - 1, 0) 创建的列表使用少量内存,并且是不可变的。文档说“返回一个不可变列表,其中包含指定对象的 n 个副本。新分配的数据对象很小(它包含对数据对象的单个引用)“。如果你看一下实现,你会发现它完全符合人们对该描述的期望。它返回一个 List 对象,该对象仅假装很大,仅保存大小和元素一次,并在询问任何索引时返回该元素。

< code>Collections.sort的问题有两个方面:

    < li >该列表不能是不可变的,但该列表是可变的。该btw还解释了当您尝试< code>set()时出现的< code > UnsupportedOperationException 。 < li >出于性能原因,它“获取包含该列表中所有元素的数组,对该数组进行排序,[并写回该列表]”。所以在这一点上,这个小小的假装列表确实被放大了,导致了你的记忆问题。

所以你需要找到一些其他的方法来排序。一个就地工作并且不为此输入交换任何内容(这是正确的,因为列表已经排序)。例如,您可以使用气泡排序,它在此输入上占用O(n)时间和O(1)空间,并且不会在此处尝试任何交换。

顺便说一句,关于“因为蒂姆索特”而得到的记忆问题:蒂姆索特真的不怪。您甚至无法进入 Timsort 部分,因为正是准备复制到数组导致了内存问题。此外,Timsort很聪明,会检测到数据已经排序,然后什么都不做。因此,如果您确实到达了 Timsort 部分,或者您可以直接将其应用于列表,Timsort 就不会造成问题。

 类似资料:
  • 问题内容: 以下代码导致OutOfMemmoryError:大约300万行的堆空间。使用64位安装,分配给JVM的内存为4 GB。 ArrayList引用的内存在while循环的每次迭代中都可以进行垃圾回收,并且由于堆空间的原因,内部JVM 在抛出OutOfMemory错误之前会调用垃圾回收()。 那么为什么会发生异常呢? 问题答案: 是的? 如果是这样,那就是您的问题:An 会对曾经写入过的 每

  • 问题内容: 我有一个包含a 和a的类。现在,我想使用gson序列化对象,但排除该字段。 如您所见,我已经尝试使用,但是似乎没有任何作用。另外,我已经将该字段设置为私有,因为我认为这会“覆盖” 但运行以下代码: 仍然会导致以下文件内容没有错误: 那我在做什么错?我现在一无所知,并且希望得到任何帮助,因为这似乎行不通。 提前致谢。 问题答案: 为了获得此结果,您需要使用注释所有字段: 并将Gson配置

  • 问题内容: 我正在研究真正了解JVM中内存分配的工作方式。我正在编写一个内存不足的应用程序:堆空间异常。 我知道我可以传入VM参数(例如Xms和Xmx)来增加JVM为正在运行的进程分配的堆空间。这是解决此问题的一种可能的解决方案,或者我可以检查代码是否存在内存泄漏并在那里解决问题。 我的问题是: 1)JVM如何实际为其分配内存?这与OS如何将可用内存传递给JVM有什么关系?或更一般而言,任何进程的

  • 我想真正了解内存分配在JVM中是如何工作的。我正在编写一个内存不足的应用程序:堆空间异常。 我知道我可以传入VM参数,如Xms和Xmx,以增加JVM为正在运行的进程分配的堆空间。这是一个可能的解决方案,或者我可以检查我的代码内存泄漏并修复那里的问题。 我的问题是: 1)JVM实际上如何为自己分配内存?这与OS如何将可用内存传递给JVM有什么关系?或者更一般地说,为任何进程分配内存实际上是如何工作的

  • 问题内容: 我要显示的最后5个输入的特定ID数据。我的SQL查询是 是DATETIME 它显示按日期而非时间排序的最后5个条目。然后在同一日期按字母顺序排序。 假设我在同一日期有3个条目,并带有差异时间 比方说 查询以上查询后 我得到的是 按日期排序,然后按字母顺序 我想要的是这个.. 还按日期和时间排序… 问题答案: 如果要最后5行(以升序排列),则需要一个子查询: 第10次阅读问题后,这可能是

  • 问题内容: 我有个约会,等等。 我想按升序和降序对日期字段进行排序 有谁可以帮忙吗? 我已经尝试过对标题字段进行排序 按标题排序可使用以下代码: 问题答案: 试试这个… 您需要在上面的代码中更改日期格式。 UPDATED: 更新DateFormat进行检查。