在Java应用程序中处理大型2D数组的最佳选项是什么?

在Java应用程序中处理大型2D数组的最佳选项是什么?,java,database,multidimensional-array,heap-memory,nosql,Java,Database,Multidimensional Array,Heap Memory,Nosql,我正在用Java(Swing)开发一个图像处理应用程序,它有很多计算。 加载大图像时会崩溃: java.lang.OutOfMemoryError:java堆空间 double matrizAdj[][] = new double[18658][18658]; 所以我决定尝试一个轻量级的、速度尽可能快的数据库来处理这个问题。考虑使用一个表作为一个2D数组,循环通过它将结果值插入到另一个表中 我也在考虑使用JNI,但由于我不熟悉C/C++并且没有必要的时间学习 目前,我的问题不是处理,而是堆过载

我正在用Java(Swing)开发一个图像处理应用程序,它有很多计算。 加载大图像时会崩溃:

java.lang.OutOfMemoryError:java堆空间

double matrizAdj[][] = new double[18658][18658];
所以我决定尝试一个轻量级的、速度尽可能快的数据库来处理这个问题。考虑使用一个表作为一个2D数组,循环通过它将结果值插入到另一个表中

我也在考虑使用JNI,但由于我不熟悉C/C++并且没有必要的时间学习

目前,我的问题不是处理,而是堆过载

我想知道解决这个问题的最佳选择是什么

编辑: 小说明:首先,我将二值化图像中的所有白色像素放入一个列表中。假设我有18k像素。然后我用这个列表执行很多操作。像方差,标准差,协方差。。。然后继续。。。最后,我不得不将两个2D数组([2][18000]&[18000][2])相乘,结果是[18000][18000]加倍,这给我带来了麻烦。然后,对该二维阵列执行其他操作,从而生成多个大型二维阵列


我无法处理需要大量RAM才能使用此应用程序的问题。

我不确定是否需要为此设置一个数据库,只需打开一个临时文件,根据需要将矩阵的一部分放在其中,然后在完成后删除该文件。您选择的任何解决方案都在一定程度上取决于您的矩阵库是否能够使用它。如果您使用的是第三方库,那么您可能仅限于它们提供的任何选项(如果有的话)。但是,如果您已经实现了自己的矩阵操作,那么肯定会使用我自己管理的临时文件。这将是最快和最轻的重量。

我不确定我是否会为此而麻烦一个数据库,只需打开一个临时文件,根据需要将矩阵的一部分放入其中,然后在完成后删除该文件。您选择的任何解决方案都在一定程度上取决于您的矩阵库是否能够使用它。如果您使用的是第三方库,那么您可能仅限于它们提供的任何选项(如果有的话)。但是,如果您已经实现了自己的矩阵操作,那么肯定会使用我自己管理的临时文件。这将是最快和最轻的重量。

我会依次推荐以下物品

  • 调查应用程序内存不足的原因。是否正在创建比所需尺寸更大的阵列或其他对象。我希望你已经这么做了。但我仍然认为这值得一提,因为这不应该被忽视
  • 如果您认为步骤1没有问题,请检查您是否在内存设置过低的情况下运行。或32位jvm
  • 如果步骤2没有问题。现在,轻量级数据库提供最佳性能并不总是正确的。如果您不需要搜索临时数据,那么实现一个轻量级数据库可能不会给您带来太多好处。但是,如果您的应用程序需要大量搜索/查询临时数据,则情况可能会有所不同。如果不需要搜索,自定义文件格式可能会快速高效

  • 我希望它能帮助您解决手头的问题:)

    我会依次推荐以下几点

  • 调查应用程序内存不足的原因。是否正在创建比所需尺寸更大的阵列或其他对象。我希望你已经这么做了。但我仍然认为这值得一提,因为这不应该被忽视
  • 如果您认为步骤1没有问题,请检查您是否在内存设置过低的情况下运行。或32位jvm
  • 如果步骤2没有问题。现在,轻量级数据库提供最佳性能并不总是正确的。如果您不需要搜索临时数据,那么实现一个轻量级数据库可能不会给您带来太多好处。但是,如果您的应用程序需要大量搜索/查询临时数据,则情况可能会有所不同。如果不需要搜索,自定义文件格式可能会快速高效

  • 我希望它能帮助您解决手头的问题:)

    好吧,看在琐事的份上,您展示的矩阵大约消耗2.6Gb的RAM。所以,这是一个衡量你需要多少记忆的基准,如果你决定追求这种技巧的话

    如果这对您来说是有效的,您可以将矩阵中的行存储到数据库中的blob中。在本例中,您将有18658行,其中包含一个序列化的
    double[18658]
    存储

    不过我不建议这样做

    更好的方法是直接使用映像文件,查看NIO和字节缓冲区,使用
    mmap
    将它们映射到程序空间

    然后您可以使用DoubleBuffers之类的东西来访问数据。这使得VM页面尽可能多地输入所需的原始文件,并且它还使数据远离Java堆(而是存储在与JVM相关联的进程RAM中)。最大的好处是它使这些庞大的数据结构远离垃圾收集器

    当然,您仍然需要机器上的物理RAM,但它不是Java堆RAM


    但这可能是为您的流程访问这些数据的最有效方式。

    好吧,为了琐事,您展示的矩阵大约消耗2.6Gb的RAM。所以,这是一个衡量你需要多少记忆的基准,如果你决定追求这种技巧的话

    如果这对您来说是有效的,您可以将矩阵中的行存储到数据库中的blob中。在本例中,您将有18658行,其中包含一个序列化的
    double[18658]
    存储

    不过我不建议这样做

    更好的方法是直接使用映像文件,查看NIO和字节缓冲区,使用
    mmap
    将它们映射到程序空间

    然后您可以使用DoubleBuffers之类的东西来访问数据。这
    public class FileDoubleMatrix implements Closeable {
    
        private final int rows;
        private final int cols;
        private final long rowSize;
        private final RandomAccessFile raf;
    
        public FileDoubleMatrix(File f, int rows, int cols) throws IOException {
            if (rows < 0 || cols < 0)
                throw new IllegalArgumentException(
                    "Rows and cols cannot be negative!");
            this.rows = rows;
            this.cols = cols;
            rowSize = cols * 8;
            raf = new RandomAccessFile(f, "rw");
            raf.setLength(rowSize * cols);
        }
    
        /**
         * Absolute get method.
         */
        public double get(int row, int col) throws IOException {
            pos(row, col);
            return get();
        }
    
        /**
         * Absolute set method.
         */
        public void set(int row, int col, double value) throws IOException {
            pos(row, col);
            set(value);
        }
    
        public void pos(int row, int col) throws IOException {
            if (row < 0 || col < 0 || row >= rows || col >= cols)
                throw new IllegalArgumentException("Invalid row or col!");
            raf.seek(row * rowSize + col * 8);
        }
    
        /**
         * Relative get method. Useful if you want to go though the whole array or
         * though a continuous part, use {@link #pos(int, int)} to position.
         */
        public double get() throws IOException {
            return raf.readDouble();
        }
    
        /**
         * Relative set method. Useful if you want to go though the whole array or
         * though a continuous part, use {@link #pos(int, int)} to position.
         */
        public void set(double value) throws IOException {
            raf.writeDouble(value);
        }
    
        public int getRows() { return rows; }
    
        public int getCols() { return cols; }
    
        @Override
        public void close() throws IOException {
            raf.close();
        }
    
    }
    
    final int rows = 10;
    final int cols = 10;
    
    try (FileDoubleMatrix arr = new FileDoubleMatrix(
                new File("array.dat"), rows, cols)) {
    
        System.out.println("BEFORE:");
        for (int row = 0; row < rows; row++) {
            for (int col = 0; col < cols; col++) {
                System.out.print(arr.get(row, col) + " ");
            }
            System.out.println();
        }
    
        // Process array; here we increment the values
        for (int row = 0; row < rows; row++)
            for (int col = 0; col < cols; col++)
                arr.set(row, col, arr.get(row, col) + (row * cols + col));
    
        System.out.println("\nAFTER:");
        for (int row = 0; row < rows; row++) {
            for (int col = 0; col < cols; col++)
                System.out.print(arr.get(row, col) + " ");
            System.out.println();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    
    // Fill the whole array with zeros using relative set
    // First position to the beginning:
    arr.pos(0, 0);
    
    // And execute a "set zero" operation
    // as many times as many elements the array has:
    for ( int i = rows * cols; i > 0; i--)
        arr.set(0);
    
    // Start with the first row:
    arr.pos(0, 0);
    
    for (int row = 0; row < rows; row++) {
        double sum = 0;
        for (int col = 0; col < cols; col++)
            sum += arr.get(); // Relative get to calculate row sum
    
        // Now set the sum to the end of row.
        // For this we have to position back, so we use the absolute set.
        arr.set(row, cols - 1, sum);
    
        // The absolute set method also moves the pointer, and since
        // it is the end of row, it moves to the first of the next row.
    }