Java交换页面
我使用两个数组构建了一个自定义hashmap。一个包含键,另一个包含值。现在,我看到有时候JVM无法为这些数组分配所需的内存,并抛出异常。是否有任何方法可以使用页面交换或任何其他方法来解决此问题 代码:Java交换页面,java,Java,我使用两个数组构建了一个自定义hashmap。一个包含键,另一个包含值。现在,我看到有时候JVM无法为这些数组分配所需的内存,并抛出异常。是否有任何方法可以使用页面交换或任何其他方法来解决此问题 代码: 公共类Test1{ 公共静态void main(字符串参数[]){ 试一试{ 整数数组[]=新整数[50000000]; 对于(int i=0;i
公共类Test1{
公共静态void main(字符串参数[]){
试一试{
整数数组[]=新整数[50000000];
对于(int i=0;i<50000000;i++)
{
数组[i]=i;
}
}
捕获(例外e){
系统输出打印ln(e);
}
}
}
编辑:
public void load(){
试一试{
FileChannel channel2=新的随机访问文件(str1,“r”).getChannel();
MappedByteBuffer mbb2=channel2.map(FileChannel.MapMode.READ_ONLY,0,channel2.size());
mbb2.order(ByteOrder.nativeOrder());
断言mbb2.remaining()==savenum*8;
for(int i=0;i
修改代码以使用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) {
}
}
}
顺便说一句:您需要一个64位JVM来同时映射这些数据。如果您有一个32位JVM,那么您需要移动映射(这是一个难题,因此如果可以,请使用64位JVM)
如果您有一个200 MB的数组,那么它应该适合32位JVM。修改代码以使用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) {
}
}
}
顺便说一句:您需要一个64位JVM来同时映射这些数据。如果您有一个32位JVM,那么您需要移动映射(这是一个难题,因此如果可以,请使用64位JVM)
如果你有一个200 MB数组,这应该适合32位JVM。
尝试用更多的堆空间启动JVM?你考虑了SQL数据库吗?页面交换是操作系统所做的事情。首先确保没有任何实际内存泄漏。(作为第一步,用一个巨大的最大堆大小来分析应用程序的内存使用情况,并检查它是否在某一点上稳定下来。)@Tudor,一直这样做都是有问题的。@arpsss为什么会有问题?你不能期望每一个应用都能使用默认设置。除此之外,在启动脚本中的一个开关?尝试用更多的堆空间启动JVM?你考虑了SQL数据库吗?页面交换是操作系统所做的事情。首先确保没有任何实际内存泄漏。(作为第一步,用一个巨大的最大堆大小来分析应用程序的内存使用情况,并检查它是否在某一点上稳定下来。)@Tudor,一直这样做都是有问题的。@arpsss为什么会有问题?你不能期望每一个应用都能使用默认设置。还有什么,启动脚本中的一个开关?谢谢。但是如何使用内存映射文件交换阵列呢?将阵列数据存储在映射的ByteBuffer中,操作系统将根据需要交换该数据的页面。确定。这是否可以快速执行(理论上)?另一件事,以前我认为,交换是由JVM完成的,它的速度和访问一个基本数组或对象的速度一样快。CPU的缓存完成了大部分工作。虽然开销很小,但您可以按照自己的意愿在内存中布局数据,从而获益匪浅。交换是由操作系统完成的,因此即使在应用程序退出或崩溃后,您执行的写入操作也可以继续。我使用内存映射文件高效地存储数据,最多可存储计算机物理内存的10倍。谢谢。但是如何使用内存映射文件交换阵列呢?将阵列数据存储在映射的ByteBuffer中,操作系统将根据需要交换该数据的页面。确定。这是否可以快速执行(理论上)?另一件事,以前我认为,交换是由JVM完成的,它的速度和访问一个基本数组或对象的速度一样快。CPU的缓存完成了大部分工作。虽然开销很小,但您可以按照自己的意愿在内存中布局数据,从而获益匪浅。交换是由操作系统完成的,因此即使在应用程序退出或崩溃后,您执行的写入操作也可以继续。我使用内存映射文件高效地存储数据,最多可存储计算机物理内存的10倍。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