简体   繁体   English

在Java中存储2D数组的最小方法

[英]Smallest way to store a 2D array in java

I am trying to generate a set of 2D int arrays that should (at least) be 6x6. 我试图生成一组(至少)应为6x6的2D int数组。 Each array stores values from 0-6. 每个数组存储0到6的值。 I tried using a simple HashSet<int[][]> to store them (with 512MB of memory), and I quickly got the error 我尝试使用一个简单的HashSet<int[][]>来存储它们(具有512MB的内存),但很快我得到了错误

Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded

only a short way into the program. 进入程序只有很短的路程。

The options that I've thought up for storing the arrays: 我考虑过的用于存储数组的选项:

  1. Store them as a long in base 7. This would only work for up to 24 (24.3717) digits, since long cannot be more than 2^63 bits. 将它们作为long存储在基数7中。由于long不能超过2^63位,因此最多只能存储24(24.3717)位数字。

  2. Store them as a String (eg {{0, 0, 0, 1}, {3, 6, 2, 0}} would become "00013620" ). 将它们存储为String (例如{{0, 0, 0, 1}, {3, 6, 2, 0}} "00013620" {{0, 0, 0, 1}, {3, 6, 2, 0}} "00013620" {{0, 0, 0, 1}, {3, 6, 2, 0}}将变成"00013620" )。 This would only take up 4x less space (I think), because a char is still 1 byte. 我认为这只会减少4倍的空间,因为char仍然是1个字节。

  3. Use something like BitSet or BigInteger ? 使用BitSetBigInteger类的东西? I have no idea what each is or how they work. 我不知道它们是什么或它们如何工作。

So my question is: What is the smallest way to store a 6 x 6 array of values from 0 - 6? 所以我的问题是: 从6到6存储6 x 6值数组的最小方法什么? Do the options above work, or is there an easier way? 以上选项有效吗,还是有更简单的方法?


Note: I have 8GB of memory that I can use, if it becomes necessary. 注意:如果有必要,我可以使用8GB的内存。

My code (it has to do with chess, if you must know): n is the size of the array (width and height), should be able to go up to (or past) 6. 我的代码(如果需要知道,它与国际象棋有关): n是数组的大小(宽度和高度),应该可以达到(或超过)6。

public static HashSet<int[][]> getBoards(int[][] data, int zero, int num) {
    HashSet<int[][]> ret = new HashSet<int[][]>(0);

    if (zero == num) {
        ret.add(data);
    } else if (zero == 0) {
        for (int y = 0; y < n; y++) {
            for (int x = 0; x < n; x++) {
                for (int i = 1; i < 7; i++) {
                    int[][] d0 = new int[n][n];
                    d0[y][x] = i;
                    ret.addAll(getBoards(d0, 1, num));
                }
            }
        }
    } else {
        for (int y = 0; y < n; y++) {
            for (int x = 0; x < n; x++) {
                if (data[y][x] == 0) continue;

                HashSet<int[]> moves = getMoves(data[y][x], x, y);

                while (moves.iterator().hasNext()) {
                    int[] m = moves.iterator().next();

                    for (int i = 0; i < 6; i++) {
                        int[][] d0 = arrayCopy(data);
                        d0[m[0]][m[1]] = i;

                        ret.addAll(getBoards(d0, zero + 1, num));
                    }
                }
            }
        }
    }

    return ret;
}

public static HashSet<int[]> getMoves(int piece, int xPos, int yPos) {
    HashSet<int[]> ret = new HashSet<int[]>(0);

    for (int y = 0; y < n; y++) {
        for (int x = 0; x < n; x++) {
            if (x == xPos && y == yPos) continue;

            switch (piece) {
            case 1:
                if (y - yPos == 1 && Math.abs(x - xPos) == 1) ret.add(new int[] {y, x});
                break;
            case 2:
                if (Math.abs(y - yPos) + Math.abs(x - xPos) == 3 && x != xPos && y != yPos) ret.add(new int[] {y, x});
                break;
            case 3:
                if (Math.abs(y - yPos) == Math.abs(x - xPos)) ret.add(new int[] {y, x});
                break;
            case 4:
                if (y == yPos || x == xPos) ret.add(new int[] {y, x});
                break;
            case 5:
                if (Math.abs(y - yPos) == Math.abs(x - xPos) || y == yPos || x == xPos) ret.add(new int[] {y, x});
                break;
            case 6:
                if (Math.abs(y - yPos) <= 1 && Math.abs(x - xPos) <= 1) ret.add(new int[] {y, x});
                break;
            default:
                throw new IllegalArgumentException("Unknown Piece Number (" + piece + ")");
            }
        }
    }

    return ret;
}

The full error: 完整错误:

Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
at ChessGenerator.arrayCopy(ChessGenerator.java:120)
at ChessGenerator.getBoards(ChessGenerator.java:71)
at ChessGenerator.getBoards(ChessGenerator.java:74)
at ChessGenerator.getBoards(ChessGenerator.java:74)
at ChessGenerator.getBoards(ChessGenerator.java:74)
at ChessGenerator.getBoards(ChessGenerator.java:74)
at ChessGenerator.getBoards(ChessGenerator.java:74)
at ChessGenerator.getBoards(ChessGenerator.java:74)
at ChessGenerator.getBoards(ChessGenerator.java:56)
at ChessGenerator.main(ChessGenerator.java:23)

EDIT: As @Louis pointed out, my use of HashSet s was causing the above error, however, I still run out of memory 编辑:正如@Louis所指出的,我对HashSet的使用导致了上述错误,但是,我仍然用尽内存

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at ChessGenerator.arrayCopy(ChessGenerator.java:119)
at ChessGenerator.getBoards(ChessGenerator.java:70)
at ChessGenerator.getBoards(ChessGenerator.java:73)
at ChessGenerator.getBoards(ChessGenerator.java:73)
at ChessGenerator.getBoards(ChessGenerator.java:73)
at ChessGenerator.getBoards(ChessGenerator.java:73)
at ChessGenerator.getBoards(ChessGenerator.java:73)
at ChessGenerator.getBoards(ChessGenerator.java:73)
at ChessGenerator.getBoards(ChessGenerator.java:58)
at ChessGenerator.main(ChessGenerator.java:23)

If you were expecting the HashSet to keep only unique int[][] s, and eliminate duplicates, that's not going to work -- the equals and hashCode implementation for int[][] (and all arrays) is identity-based. 如果您期望HashSet仅保留唯一的int[][]并消除重复项,那将不起作用hashCode int[][] (和所有数组)的equalshashCode实现是基于身份的。 If you had been depending on uniqueness to keep the number of distinct arrays small, that's not going to work; 如果您一直依靠唯一性来保持不同数组的数量少,那将是行不通的; you're going to have to wrap them in a type implementing a correct hashCode and equals . 您将必须将它们包装在实现正确的hashCodeequals的类型中。

You seem to be creating a LOT of boards, it is hard to follow, but it seems you are basically generating a large portion of all arrays of size 6X6 where each cell can has any value of 1,2,..,6. 您似乎要创建很多板,这很难遵循,但是似乎您基本上在生成6X6大小的所有数组的很大一部分,其中每个单元格可以具有1,2,。,6的任何值。

The number of such arrays is 6^36 ~= 10^28. 此类数组的数量为6 ^ 36〜= 10 ^ 28。

This means, even if each array will be only one byte (it cannot be), you are still going to need 10^16 TB to hold all of them. 这意味着,即使每个阵列只有一个字节(不能为一个字节),您仍然需要10 ^ 16 TB的空间来容纳所有字节。

I suggest you look for an alternative that does not include generating all possible arrays explicitly. 我建议您寻找一种不包括显式生成所有可能数组的替代方法。


As a side note, that lowest possible number of bits to represent your object is ceil(log_2(6^36)) = 94 , but that's going to be a lot of work to get this optimal result, and I won't advise it. 附带说明一下,表示对象的最低位数是ceil(log_2(6^36)) = 94 ,但是要获得最佳效果将需要大量工作,我不建议这样做。

The most straightforward yet still memory-efficient way is to store each array as two long s, with each field taking up 3 bits (that's 3*36=108 useful bits in total, with an overhead of 20 unused bits). 最直接但仍具有内存效率的方法是将每个数组存储为两个long ,每个字段占用3位(总共3 * 36 = 108个有用位,开销为20个未使用位)。 Although the theoretical limit is less than that, you'd almost certainly want your structures aligned to word boundaries, therefore you're not really losing anything. 尽管理论上的限制还不及此,但是您几乎可以肯定希望结构与单词边界对齐,因此您并没有真正失去任何东西。 What you win though is that accessing individual fields is simple and fast, only requiring bit-masking and shifting operations. 但是,您获得的好处是,访问各个字段既简单又快速,只需要位屏蔽和移位操作即可。

I would also take a look at off-heap storage options, to eliminate all object overhead. 我还将研究堆外存储选项,以消除所有对象开销。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM