哪个在内存方面更好、更高效,一个大数组还是多个数组?

Which is better and efficient memory-wise, a big array or multiple arrays?

我正在开发的应用程序,用户可以在其中模拟测试并离线回答。我有一个软件可以从我的数据库中获取数据(问题、备选方案、问题类型等)并将它们转换成数组。

我不知道哪个是最有效的(内存方面):创建一个包含所有问题的大数组的对象或创建单独的对象(例如,针对每个主题)每个数组或创建多个同一对象中的数组。创建一个包含大约 1000 个数组的数组是否可以,还是拆分该数组更好,在...10 个数组中,每个数组包含 100 个数组?

P.S:在测试期间我只会使用数组中的 30 个项目,所以我将从大数组(或多个数组)中取出条目并将它们添加到小的 30 个条目中将根据用户输入创建的数组。

我想用什么

我想要一个大数组,因为对我来说排序和创建随机测试会更容易,有些人说 1000 个条目并不算多,所以我想我会坚持使用一个大数组。什么会太大? 1 万、10 万?

老实说,1000 不是很大,但它关系到元素的大小。

不过,以后你的entry size会变大,所以肯定不想每次都改逻辑。因此,您必须以高效的方式进行设计,这对于增长数据也应该是富有成效的。

内存问题 - 如果将所有数据存储在一个数组或 10 个数组中,两者将占用几乎相同的内存量,差异很小), 但是,如果您有 10 个阵列,那么管理可能会很困难,随着需求的增长,您可能会面临更多的复杂性。

我可以建议您使用单个数组,这对于管理非常有用。您也可以考虑 LinkedList,这对于更快的搜索结果非常有用。

您需要考虑三种效率

  • 内存效率;即最小化 RAM 利用率
  • CPU效率
  • 程序员效率;即最大限度地减少您花在编写、编写测试用例、调试和维护代码上的宝贵时间。

请注意,上述标准相互矛盾。

内存效率

给出的 Java 中引用数组 N 的内存大小(以字节为单位)
  N * reference_size + array_header_size + padding

其中:

  • reference_size 是以字节为单位的引用大小(通常为 4 或 8)
  • array_header_size 通常是 12 个字节
  • padding大于等于0,小于堆节点大小粒度

数组本身也有一个唯一的引用,它必须保存在内存中的某个地方。

因此,如果将一个大数组拆分为 M 个较小的数组,您将至少使用 (M - 1) * 16 个额外的 RAM 字节,甚至可能更多。另一方面,我们在这里谈论的是字节,而不是千字节或兆字节。所以这并不重要。

CPU效率

这更难预测。 CPU 利用率效果在很大程度上取决于您对数组的处理方式以及处理方式。

如果您只是简单地下标(索引)数组,则该操作不依赖于数组大小。但是如果你有多个数组(例如数组数组),那么在确定下标中的数组时会有额外的开销。

如果您在数组中搜索某些内容,那么您需要搜索的数组越大,所需的时间就越长(平均而言)。但是,如果您将一个大数组拆分为多个较小的数组,那不一定有帮助……除非您事先知道要搜索哪个较小的数组。

程序员效率

如果您使用多个数组而不是一个数组,可能会使您的代码更加复杂。更复杂的代码意味着更多的程序员在应用程序开发和维护生命周期的所有阶段付出更多的努力。很难量化需要付出多少额外努力。然而,程序员的努力意味着成本(支付工资)和时间(截止日期、上市时间等),这可能会超过内存和 CPU.

的任何小的节省。

可扩展性

你说:

Some people are saying 1000 entries aren't too much, so I think I'll stick to a big array. What would be too big? 10k, 100k?

再次强调,这取决于上下文。实际上,用于 X 的 100K 个实例的数组的内存在很大程度上取决于 X 的平均大小。您很可能 运行 内存不足来表示 X 实例而不是数组。

因此,如果您希望您的应用程序无限扩展,您可能应该更改架构,以便它从数据库中获取问题/答案按需,而不是加载它们启动时全部存入内存。

过早的优化

Donald Knuth 经常被(错误地)引用1 说:

"Premature optimization is the root of all evil."

他指出的是,程序员倾向于优化不需要优化的东西,或者根据不正确的直觉将精力花在优化代码的错误区域上。

我对此的建议如下:

  • 不要过早进行 fine-grained 优化。 (这并不意味着您应该忽略设计和编码阶段的效率问题,但我的建议是只考虑主要问题;例如算法的复杂性、API 和数据库查询的粒度等。尤其是事情以后要解决这个问题需要付出很多努力。)

  • 如果以及何时进行优化,请科学地进行:

    • 使用基准衡量性能。
    • 使用分析器查找性能热点并将您的精力集中在这些方面。
    • 使用基准查看优化是否有所改善,并放弃没有帮助的优化。
  • 为您的优化设置一些现实的目标(或时间限制),并在达到这些目标时停止。

1 - 完整的引文更加细致。查一下。事实上,高德纳本人是在引用托尼·霍尔的话。要对此进行更深入的探讨,请参阅 https://ubiquity.acm.org/article.cfm?id=1513451