有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

优化大型Java数据阵列的处理和管理

我正在编写一些相当CPU密集的并发数字代码,这些代码将处理存储在Java数组中的大量数据(例如,大量双倍[100000]秒)。有些算法可能会在几天内运行数百万次,因此获得最大的稳态性能是一个高度优先事项

本质上,每个算法都是一个Java对象,它有一个方法API,类似于:

   public double[] runMyAlgorithm(double[] inputData);

或者,可以将引用传递到数组以存储输出数据:

   public runMyAlgorithm(double[] inputData, double[] outputData);

鉴于这一需求,我试图确定分配/管理阵列空间的最佳策略。算法通常需要大量的临时存储空间。他们还将把大型数组作为输入,创建大型数组作为输出

我正在考虑的选项包括:

  • 每当需要时,总是将新数组作为局部变量分配(例如新的double[100000])。可能是最简单的方法,但会产生大量垃圾
  • 预先分配临时数组,并将它们存储为algorithm对象中的最终字段——最大的缺点是,这意味着在任何时候只有一个线程可以运行该算法
  • 在ThreadLocal存储中保留预先分配的临时阵列,以便线程可以在需要时使用固定数量的临时阵列空间。由于多个线程将同时运行同一个算法,因此需要ThreadLocal
  • 将大量数组作为参数传递(包括算法要使用的临时数组)。不太好,因为如果调用者必须负责提供临时数组空间,那么它会使算法API非常难看
  • 分配非常大的数组(例如double[10000000]),但也为算法提供数组中的偏移量,以便不同的线程将独立使用数组的不同区域。显然需要一些代码来管理数组范围的偏移和分配

关于哪种方法最好(以及为什么)有什么想法吗


共 (1) 个答案

  1. # 1 楼答案

    在Java中使用内存时,我注意到以下几点。如果你的内存需求模式很简单(主要是2-3种类型的内存分配),你通常可以比默认的分配器更好。您可以在应用程序启动时预先分配一个缓冲池,并根据需要使用它们,也可以转到另一个路径(在开始时分配一个巨大的阵列,并在需要时提供其中的一部分)。实际上,您正在编写自己的内存分配器。但很可能你的工作会比Java的默认分配器差

    我可能会尝试以下操作:标准化缓冲区大小并正常分配。这样,一段时间后,唯一的内存分配/释放将是固定大小的,这将极大地帮助垃圾收集器快速运行。我要做的另一件事是确保在算法设计时,任何一点所需的总内存不会超过机器内存的80-85%,以免无意中触发完全收集

    除了这些启发法,我可能还会测试我选择的任何解决方案,看看它在实践中是如何工作的