用Java表示100K X 100K矩阵

时间:2009-12-20 07:29:02

标签: java arrays

如何在Java中存储100K X 100K矩阵?

我不能用正常的数组声明来做,因为它抛出java.lang.OutofMemoryError

9 个答案:

答案 0 :(得分:14)

Colt库有一个Java的稀疏矩阵实现。

您也可以使用Berkeley DB作为存储引擎。

现在,如果您的计算机有足够的实际RAM(至少9 GB可用),您可以在Java命令行中增加堆大小。

答案 1 :(得分:10)

如果矩阵中的绝大多数条目都为零(或者甚至是其他一些常数值),则稀疏矩阵将是合适的。否则,可能会重写您的算法,以便整个矩阵不会同时存在。例如,您可以一次生成和使用一行。

答案 2 :(得分:7)

100,000 x 100,000 = 10,000,000,000(100亿)条目。即使您存储单字节条目,仍然在10 GB附近 - 您的机器甚至还有那么多物理内存,更不用说有意愿将这么多内容分配给单个进程了吗?

你可能需要考虑某种方式,只在任何给定时间将矩阵的一部分保留在内存中,其余的则缓存在磁盘上。

答案 3 :(得分:7)

听起来你需要一个稀疏矩阵。其他人已经提出了可以满足您需求的良好第三方实施......

根据您的应用程序,只需使用Map作为矩阵数据的后备存储,就可以在没有第三方矩阵库的情况下离开。有点......

public class SparseMatrix<T> {
    private T defaultValue;
    private int m;
    private int n;
    private Map<Integer, T> data = new TreeMap<Integer, T>();
    /// create a new matrix with m rows and n columns
    public SparseMatrix(int m, int n, T defaultValue) {
        this.m = m;
        this.n = n;
        this.defaultValue = defaultValue;
    }
    /// set value at [i,j] (row, col)
    public void setValueAt(int i, int j, T value) {
        if (i >= m || j >= n || i < 0 || j < 0) 
            throw new IllegalArgumentException(
                    "index (" + i + ", " +j +") out of bounds");        
        data.put(i * n + j, value);
    }
    /// retrieve value at [i,j] (row, col)
    public T getValueAt(int i, int j) {
        if (i >= m || j >= n || i < 0 || j < 0) 
            throw new IllegalArgumentException(
                    "index (" + i + ", " +j +") out of bounds");
        T value = data.get(i * n + j);
        return value != null ? value : defaultValue;
    }
}

说明SparseMatrix使用的简单测试用例是:

public class SparseMatrixTest extends TestCase {
    public void testMatrix() {
        SparseMatrix<Float> matrix = 
            new SparseMatrix<Float>(100000, 100000, 0.0F);
        matrix.setValueAt(1000, 1001, 42.0F);
        assertTrue(matrix.getValueAt(1000,1001) == 42.0);
        assertTrue(matrix.getValueAt(1001,1000) == 0.0);        
    }   
}

这不是最有效的方法,因为矩阵中的每个非默认条目都存储为Object。根据您期望的实际值的数量,这种方法的简单性可能胜过集成第三方解决方案(并且可能再次根据您的情况处理其许可证)。

在上面的SparseMatrix实现中添加乘法之类的矩阵运算应该是直截了当的(并留给读者练习; - )

答案 4 :(得分:5)

根据您拥有的内存量,阵列的实际稀疏程度以及访问模式的不同,有许多可能的解决方案。

如果100K * 100K * 8的计算量小于机器上供JVM使用的物理内存量,那么简单的非稀疏阵列是可行的解决方案。

如果数组稀疏,(例如)75%或更多元素为零,则可以使用稀疏数组库来节省空间。已经提出了各种替代方案,但在所有情况下,如果能够为您节省足够的成本,您仍然需要解决问题。计算出有多少非零元素,乘以8(给你双精度)和(比如)4来计算稀疏数组的开销。如果这小于您可以为JVM提供的物理内存量,那么稀疏阵列是一种可行的解决方案。

如果稀疏和非稀疏数组(在内存中)不起作用,事情会变得更复杂,任何解决方案的可行性将取决于数组数据的访问模式。

  • 一种方法是将数组表示为以MappedByteBuffer形式映射到内存的文件。假设您没有足够的物理内存来将整个文件存储在内存中,那么您将很难进入虚拟内存系统。因此,最好是您的算法只需要随时对阵列的连续部分进行操作。否则,你可能会死于交换。

  • 第二种方法是第一种方法的变体。一次将数组/文件映射到一个部分,完成后,取消映射并移至下一部分。这仅适用于算法在节中处理数组的情况。

  • 第三种方法是使用像BDB这样的轻量级数据库来表示数组。这将比任何内存中的解决方案慢,因为读取数组元素将转换为光盘访问。但如果你弄错了它就不会像内存映射方法那样杀死系统。 (如果你在Linux / Unix上执行此操作,系统的磁盘块缓存可能会加快速度,具体取决于算法的阵列访问模式)

  • 第四种方法是使用分布式内存缓存。这会将光盘i / o替换为网络i / o,很难说这是好事还是坏事。

  • 第五种方法是分析您的算法,看它是否适合作为分布式算法实现;例如数组的各个部分以及算法的相应部分在不同的机器上。

答案 5 :(得分:4)

您可以升级到此计算机:

http://www.azulsystems.com/products/compute_appliance.htm

864个处理器内核和768 GB内存,只需要在某个地方购买一个家庭住宅。

答案 6 :(得分:3)

好吧,我建议你增加jvm中的内存,但是你需要大量的内存,因为你正在谈论100亿个项目。它(很少)可能有大量内存或群集jvm,但这可能是错误的答案。

  • 你得到outOfmemory,因为如果你声明int [1000],内存会被立即分配(另外双倍占用比int更多的空间 - 一个int表示也会节省你的空间)。也许你可以替换一个更有效的数组实现(如果你有许多空条目查找“稀疏矩阵”表示)。

  • 您可以将片段存储在外部系统中,例如memcached或内存映射缓冲区。

这里有很多好的建议,也许如果你发布了一个更详细的问题描述,你试图解决的问题可能更具体。

答案 7 :(得分:2)

你应该尝试一个“外部”包来处理矩阵,但我从来没有这样做,可能像jama那样。

答案 8 :(得分:2)

除非您有100K x 100K x 8~80GB的内存,否则无法在内存中创建此矩阵。您可以在磁盘上创建此矩阵并使用内存映射访问它。但是,使用这种方法会非常慢。

你想做什么?您可能会发现以不同方式表示数据会更有效率。