我使用两个数组构建了一个自定义hashmap。一个包含键另一个值。现在,我看到有时JVM无法为这些数组分配所需的内存并抛出异常。是否有任何方法可以使用页面交换或任何其他方法来解决这个问题?
代码:
public class Test1{
public static void main(String args[]){
try {
int arrays[] = new int[50000000] ;
for ( int i = 0; i < 50000000 ; i++)
{
arrays[i] = i ;
}
}
catch(Exception e){
System.out.println(e) ;
}
}
}
编辑:
public void load() {
try {
FileChannel channel2 = new RandomAccessFile(str1, "r").getChannel();
MappedByteBuffer mbb2 = channel2.map(FileChannel.MapMode.READ_ONLY, 0, channel2.size());
mbb2.order(ByteOrder.nativeOrder());
assert mbb2.remaining() == savenum * 8;
for (int i = 0; i < savenum; i++) {
long l = mbb2.getLong();
keys[i] = l;
}
channel2.close();
FileChannel channel3 = new RandomAccessFile(str2, "r").getChannel();
MappedByteBuffer mbb3 = channel3.map(FileChannel.MapMode.READ_ONLY, 0, channel3.size());
mbb3.order(ByteOrder.nativeOrder());
assert mbb3.remaining() == savenum * 4;
for (int i = 0; i < savenum; i++) {
int l1 = mbb3.getInt();
values[i] = l1;
}
channel3.close();
} catch (Exception e) {
System.out.println(e);
}
}
public void save() {
try {
FileChannel channel = new RandomAccessFile(str1, "rw").getChannel();
MappedByteBuffer mbb = channel.map(FileChannel.MapMode.READ_WRITE, 0, savenum * 8);
mbb.order(ByteOrder.nativeOrder());
for (int i = 0; i < savenum; i++) {
mbb.putLong(keys[i]);
}
channel.close();
FileChannel channel1 = new RandomAccessFile(str2, "rw").getChannel();
MappedByteBuffer mbb1 = channel1.map(FileChannel.MapMode.READ_WRITE, 0, savenum * 4);
mbb1.order(ByteOrder.nativeOrder());
for (int i = 0; i < savenum; i++) {
mbb1.putInt(values[i]);
}
channel1.close();
} catch (Exception e) {
System.out.println("IOException : " + e);
}
}
答案 0 :(得分:1)
修改代码以使用IntBuffer和LongBuffer
class LongIntParallelHashMultimap {
private static final int NULL = 0;
private final FileChannel channel1, channel2;
private final LongBuffer keys;
private final IntBuffer values;
private final int capacity;
private int size;
public LongIntParallelHashMultimap(int capacity, String basename) throws IOException {
assert (capacity & (capacity - 1)) == 0 : "Capacity " + capacity + " must be a power of 2";
this.capacity = capacity;
channel1 = new RandomAccessFile(basename + ".keys", "rw").getChannel();
keys = channel1.map(FileChannel.MapMode.READ_WRITE, 0, capacity * 8).order(ByteOrder.nativeOrder()).asLongBuffer();
// load keys into memory
for(int i=0;i<capacity;i+=512) keys.get(i);
channel2 = new RandomAccessFile(basename + ".values", "rw").getChannel();
values = channel2.map(FileChannel.MapMode.READ_WRITE, 0, capacity * 4).order(ByteOrder.nativeOrder()).asIntBuffer();
for(int i=0;i<capacity;i+=1024) values.get(i);
}
public void put(long key, int value) {
long key1 = key + 1;
int index = indexFor(key1);
while (keys.get(index) != NULL) {
index = successor(index);
}
values.put(index, value);
keys.put(index, key1);
++size;
}
/**
* Uses a pre-allocated array and return the count of matches.
*/
public int get(long key, int[] hits) {
long key1 = key + 1;
int index = indexFor(key1);
int hitIndex = 0;
while (keys.get(index) != NULL) {
if (keys.get(index) == key1) {
hits[hitIndex] = values.get(index);
++hitIndex;
}
index = successor(index);
}
return hitIndex;
}
private int indexFor(long key) {
return Math.abs((int) ((key * 5700357409661598721L) & (capacity - 1)));
}
private int successor(int index) {
return (index + 1) & (capacity - 1);
}
public int size() {
return size;
}
public void close() {
try {
channel1.close();
channel2.close();
} catch (IOException ignored) {
}
try {
((DirectBuffer) keys).cleaner().clean();
((DirectBuffer) values).cleaner().clean();
} catch (Throwable notSupportedOnThisPlatform) {
}
}
}
要允许操作系统交换数据结构的页面,您需要使用堆内存或内存映射文件。内存映射文件更易于管理,并且可以达到硬盘大小。
long heap = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
RandomAccessFile raf = new RandomAccessFile("array.dat", "rw");
IntBuffer map = raf.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, 1 << 30).order(ByteOrder.nativeOrder()).asIntBuffer();
for (int i = 0; i < map.capacity(); i++)
map.put(i, i);
long heap2 = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
System.out.printf("Wrote %,d int values, heap used %,d bytes approx%n", map.capacity(), heap2 - heap);
打印
Wrote 268,435,456 int values, heap used 0 approx
BTW:你需要一个64位的JVM来同时映射这些数据。如果你有一个32位的JVM,你需要移动映射(如果可以的话,这是一个痛苦的使用64位JVM)
如果你有一个200 MB的阵列,这应该适合32位JVM。