什么是非常大的 HashMap 的有效替代方案?
What is an efficient alternative for an extremely large HashMap?
我正在尝试使用 'meet-in-the-middle' 攻击来破解对称加密。为此,我需要存储 2**32 个整数对。我正在存储从 4 字节密文到 4 字节密钥的映射。
起初我尝试使用数组,但后来我意识到你不能在 java 中有这么大的数组(最大大小受 Integer.MAX_VALUE
限制)。
现在我正在使用 HashMap,但是当映射变大时,即使使用 -Xmx8192M
.
将最大内存增加到 8GB,它也会变得太慢
什么是一个非常大的 HashMap 的有效替代方案?
这是我目前用来填充哈希图的代码:
HashMap<Integer, Integer> map = new HashMap<>(Integer.MAX_VALUE);
// Loop until integer overflow
for (int k = 1; k != 0; k++)
map.put(encrypt_left(c, k), k);
我还没有看到这段代码完成,甚至在让它 运行 几个小时之后也是如此。进度记录显示前 2**24 个值是在 22 秒内创建的,但随后性能迅速下降。
I'm storing the mapping from a 4-byte cyphertext to a 4-byte key.
为了方便,4 个字节是一个 int
。如您所见,数组大小受 Integer.MAX_VALUE
限制。这表明您 可以 使用数组——但有一个小问题。整数是有符号的,但数组只允许值 >=0.
所以你创建了两个数组:一个用于正密文,一个用于负密文。然后你只需要确保你已经给了 JVM 足够的堆。
那是多少堆?
4 个字节 * Integer.MAX_VALUE
* 2 个数组
= 17179869176 字节
= ~16.0 GB。
构建彩虹时table,请考虑您将要生成的数据的大小。还要考虑一个事实,这个问题可以在没有大量 RAM 的情况下解决。这是通过使用文件而不是将所有内容放入内存来完成的。通常,您构建的文件大小适合您的文件缓冲区。例如 4096 字节或 8192 字节。如果你得到一个密钥,你只需将它除以文件缓冲区的大小,加载文件并查看 mod x 位置。
棘手的部分是您需要布置加密数据,而不是密钥。所以你从虚拟文件开始,在加密数据的位置写入密钥数据。
这么说吧,你的密钥是1026,加密后的数据是126。写入1026的flke是0.rbt因为126*4 byte / 4096 = 0。位置是126*4 byte。
当然,你需要 nio 类。
这是大数据问题,在这种情况下更像是一个大内存问题。为了性能,计算应该在内存中完成。使用 Hazelcast 分布式 HashMap
。它非常易于使用且非常高效。
您可以使用 2 台或更多机器来解决您的问题。
示例用法:
HazelcastInstance hzInstance = Hazelcast.newHazelcastInstance();
Map<Integer, Integer> map = hzInstance.getMap("map1");
map.put(x,y);
..
按照@MattBall 的建议,我实现了自己的 BigArray
,它由 4 个单独的数组组成一个 32 位长度的数组。
运行 如果没有建议的 JVM 参数,这将导致 OutOfMemoryError。将其与建议的 JVM 参数一起使用但内存太少可能会导致您的机器崩溃。
/**
* Array that holds 2**32 integers, Implemented as four 30-bit arrays.
* <p>
* Requires 16 GB RAM solely for the array allocation.
* <p>
* Example JVM Arguments: <code>-Xmx22000M -Xms17000M</code>
* <p>
* This sets the max memory to 22,000 MB and the initial memory to 17,000 MB
* <p>
* WARNING: don't use these settings if your machine does not have this much RAM.
*
* @author popovitsj
*/
public class BigArray
{
private int[] a_00= new int[1 << 30];
private int[] a_01 = new int[1 << 30];
private int[] a_10 = new int[1 << 30];
private int[] a_11 = new int[1 << 30];
private static final int A_00 = 0;
private static final int A_01 = 1 << 30;
private static final int A_10 = 1 << 31;
private static final int A_11 = 3 << 30;
private static final int A_30 = A_01 - 1;
public void set(int index, int value)
{
getArray(index)[index & A_30] = value;
}
public int get(int index)
{
return getArray(index)[index & A_30];
}
private int[] getArray(int index)
{
switch (index & A_11)
{
case (A_00):
return a_00;
case (A_01):
return a_01;
case (A_10):
return a_10;
default:
return a_11;
}
}
}
我正在尝试使用 'meet-in-the-middle' 攻击来破解对称加密。为此,我需要存储 2**32 个整数对。我正在存储从 4 字节密文到 4 字节密钥的映射。
起初我尝试使用数组,但后来我意识到你不能在 java 中有这么大的数组(最大大小受 Integer.MAX_VALUE
限制)。
现在我正在使用 HashMap,但是当映射变大时,即使使用 -Xmx8192M
.
什么是一个非常大的 HashMap 的有效替代方案?
这是我目前用来填充哈希图的代码:
HashMap<Integer, Integer> map = new HashMap<>(Integer.MAX_VALUE);
// Loop until integer overflow
for (int k = 1; k != 0; k++)
map.put(encrypt_left(c, k), k);
我还没有看到这段代码完成,甚至在让它 运行 几个小时之后也是如此。进度记录显示前 2**24 个值是在 22 秒内创建的,但随后性能迅速下降。
I'm storing the mapping from a 4-byte cyphertext to a 4-byte key.
为了方便,4 个字节是一个 int
。如您所见,数组大小受 Integer.MAX_VALUE
限制。这表明您 可以 使用数组——但有一个小问题。整数是有符号的,但数组只允许值 >=0.
所以你创建了两个数组:一个用于正密文,一个用于负密文。然后你只需要确保你已经给了 JVM 足够的堆。
那是多少堆?
4 个字节 * Integer.MAX_VALUE
* 2 个数组
= 17179869176 字节
= ~16.0 GB。
构建彩虹时table,请考虑您将要生成的数据的大小。还要考虑一个事实,这个问题可以在没有大量 RAM 的情况下解决。这是通过使用文件而不是将所有内容放入内存来完成的。通常,您构建的文件大小适合您的文件缓冲区。例如 4096 字节或 8192 字节。如果你得到一个密钥,你只需将它除以文件缓冲区的大小,加载文件并查看 mod x 位置。 棘手的部分是您需要布置加密数据,而不是密钥。所以你从虚拟文件开始,在加密数据的位置写入密钥数据。
这么说吧,你的密钥是1026,加密后的数据是126。写入1026的flke是0.rbt因为126*4 byte / 4096 = 0。位置是126*4 byte。 当然,你需要 nio 类。
这是大数据问题,在这种情况下更像是一个大内存问题。为了性能,计算应该在内存中完成。使用 Hazelcast 分布式 HashMap
。它非常易于使用且非常高效。
您可以使用 2 台或更多机器来解决您的问题。
示例用法:
HazelcastInstance hzInstance = Hazelcast.newHazelcastInstance();
Map<Integer, Integer> map = hzInstance.getMap("map1");
map.put(x,y);
..
按照@MattBall 的建议,我实现了自己的 BigArray
,它由 4 个单独的数组组成一个 32 位长度的数组。
运行 如果没有建议的 JVM 参数,这将导致 OutOfMemoryError。将其与建议的 JVM 参数一起使用但内存太少可能会导致您的机器崩溃。
/**
* Array that holds 2**32 integers, Implemented as four 30-bit arrays.
* <p>
* Requires 16 GB RAM solely for the array allocation.
* <p>
* Example JVM Arguments: <code>-Xmx22000M -Xms17000M</code>
* <p>
* This sets the max memory to 22,000 MB and the initial memory to 17,000 MB
* <p>
* WARNING: don't use these settings if your machine does not have this much RAM.
*
* @author popovitsj
*/
public class BigArray
{
private int[] a_00= new int[1 << 30];
private int[] a_01 = new int[1 << 30];
private int[] a_10 = new int[1 << 30];
private int[] a_11 = new int[1 << 30];
private static final int A_00 = 0;
private static final int A_01 = 1 << 30;
private static final int A_10 = 1 << 31;
private static final int A_11 = 3 << 30;
private static final int A_30 = A_01 - 1;
public void set(int index, int value)
{
getArray(index)[index & A_30] = value;
}
public int get(int index)
{
return getArray(index)[index & A_30];
}
private int[] getArray(int index)
{
switch (index & A_11)
{
case (A_00):
return a_00;
case (A_01):
return a_01;
case (A_10):
return a_10;
default:
return a_11;
}
}
}