Java交换页面

Java交换页面,java,Java,我使用两个数组构建了一个自定义hashmap。一个包含键,另一个包含值。现在,我看到有时候JVM无法为这些数组分配所需的内存,并抛出异常。是否有任何方法可以使用页面交换或任何其他方法来解决此问题 代码: 公共类Test1{ 公共静态void main(字符串参数[]){ 试一试{ 整数数组[]=新整数[50000000]; 对于(int i=0;i

我使用两个数组构建了一个自定义hashmap。一个包含键,另一个包含值。现在,我看到有时候JVM无法为这些数组分配所需的内存,并抛出异常。是否有任何方法可以使用页面交换或任何其他方法来解决此问题

代码:

公共类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