Java 缓冲区与不安全-JVM外部

Java 缓冲区与不安全-JVM外部,java,directmemory,Java,Directmemory,我需要在可用RAM中使用GC无法控制的空间。我读了几篇同样的文章,介绍了两种方法。它们在以下代码中指定 package com.directmemory; 导入java.lang.reflect.Field; 导入java.nio.ByteBuffer 导入sun.misc.Unsafe 公共类DirectMemoryTest{ public static void main(String[] args) { //Approach 1 ByteBuffer directByt

我需要在可用RAM中使用GC无法控制的空间。我读了几篇同样的文章,介绍了两种方法。它们在以下代码中指定

package com.directmemory;
导入java.lang.reflect.Field; 导入java.nio.ByteBuffer

导入sun.misc.Unsafe

公共类DirectMemoryTest{

public static void main(String[] args) {

    //Approach 1
    ByteBuffer directByteBuffer = ByteBuffer.allocateDirect(8);
    directByteBuffer.putDouble(1.0);
    directByteBuffer.flip();
    System.out.println(directByteBuffer.getDouble());

    //Approach 2
    Unsafe unsafe = getUnsafe();
    long pointer = unsafe.allocateMemory(8);
    unsafe.putDouble(pointer, 2.0);
    unsafe.putDouble(pointer+8, 3.0);

    System.out.println(unsafe.getDouble(pointer));
    System.out.println(unsafe.getDouble(pointer+8));
    System.out.println(unsafe.getDouble(pointer+16));
}

public static Unsafe getUnsafe() {
    try {
        Field f = Unsafe.class.getDeclaredField("theUnsafe");
        f.setAccessible(true);
        return (Unsafe) f.get(null);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}
}

我有几个问题

1) 为什么我要注意代码中提到的方法1,因为根据我的理解ByteBuffer.allocateDirect()无法返回存储容量大于2GB的缓冲区?因此,如果我的要求是存储3 GB的数据,我必须创建一个新的缓冲区并将数据存储在那里,这意味着除了存储数据外,我还需要负责识别相应的缓冲区(从“n”个缓冲区列表中),该缓冲区维护指向直接内存的指针

2) 方法2不是比方法1快一点吗?因为我不必先找到缓冲区,然后找到数据,我只需要一个对象字段的索引机制,使用getDouble/getInt方法并传递绝对地址

3) 直接内存的分配(说堆外内存是对的吗?)与PID有关吗?如果在一台机器上,我有两个java进程,PID 1和PID 2中的allocateMemory调用会给我提供永不相交的内存块来使用吗


4) 为什么最后一个sysout语句没有生成0.0?其思想是,每双精度使用8个字节,因此我将1.0存储在allocateMemory返回的地址上,比如地址=1,2.0存储在地址1+8上,地址为9,然后停止。那么默认值不应该是0吗?

< P>一点要考虑的是Sun.MISC.UnStand不是一个支持的API。它将被其他东西所取代()

1) 如果您的代码必须在Java8到Java10(以及更高版本)中保持不变地运行,那么使用ByteBuffers的方法1就是一种选择

如果您准备用Java 9/Java 10中的任何替换替换sun.misc.Unsafe,那么您最好使用sun.misc.Unsafe

2) 对于大于2 GB的超大数据结构,由于方法1中需要额外的间接寻址,因此方法2可能会更快。然而,如果没有一个可靠的(微观)基准,我就不会对它下任何赌注

3) 分配的内存始终绑定到当前运行的JVM。因此,在同一台机器上运行两个JVM时,您将不会获得交叉内存

4) 您正在分配8个字节的未初始化的内存。您现在唯一可以合法访问的内存量是8字节。对于超出分配大小的内存,不作任何保证

4a)您正在超出分配的内存写入8个字节(
unsafe.putdoull(指针+8,3.0);
),这已经导致内存损坏,并可能导致下一次内存分配时JVM崩溃


4b)您正在读取超出分配内存的16个字节,这(取决于您的处理器体系结构和操作系统以及以前的内存使用情况)可能会导致JVM立即崩溃。

感谢您提供的所有要点。我认为ByteBuffer战胜不安全的第一点是,ByteBuffer允许您以受控方式添加内存,并具有访问位置和限制的API,因此我们可以决定是否创建新缓冲区,我不确定不安全是否提供了新缓冲区。所以,如果应用程序要求使用不安全的方法分配更多内存,那么使用reallocateMemory方法不是很直观吗?这有意义吗?或者您认为使用不安全的重新分配非常直观?如果您在
C
中编写代码,您将使用类似的函数(malloc/realloc/free),因此使用reallocatemory是有意义的