java - Buffer 与 Unsafe - 在 JVM 之外

标签 java directmemory

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

package com.directmemory;

导入java.lang.reflect.Field; 导入 java.nio.ByteBuffer;

导入 sun.misc.Unsafe;

公共(public)类 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 ' buffers) 维护指向直接内存的指针。

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

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

4) 为什么最后一个 sysout 语句的结果不是 0.0?这个想法是每个 double 使用 8 个字节,所以我将 1.0 存储在 allocateMemory 返回的地址处,比如地址 = 1,地址 1+8 处的 2.0 即 9,然后停止。那么默认值不应该是 0.0 吗?

最佳答案

需要考虑的一点是 sun.misc.Unsafe 不是受支持的 API。它将被其他东西取代 ( http://openjdk.java.net/jeps/260 )

1) 如果您的代码必须在 Java 8 到 Java 10(及更高版本)中不加改动地运行,则使用 ByteBuffers 的方法 1 是可行的方法。

如果您准备好用 Java 9/Java 10 中的任何替换替换 sun.misc.Unsafe 的使用,您可能会选择 sun.misc.Unsafe。

2) 对于超过 2 GB 的非常大的数据结构,方法 2 可能更快,因为方法 1 中需要额外的间接寻址。但是,如果没有可靠的(微观)基准,我不会在上面打赌。

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

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

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

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

关于java - Buffer 与 Unsafe - 在 JVM 之外,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34469568/

相关文章:

java - 如何将第一个图像从 ArrayList<string> 设置到 imageView 中

java - Authorize.net创建ARB并获取Id

java - ScheduledExecutorService 中的线程排队

java - 需要添加 SOAP 安全 token

java - 堆外缓存 DirectMemory 是否已准备好投入生产?活跃吗?

java - 如何获取 Netty 4 应用程序的直接内存快照

java - 为 Java 应用程序设置 MaxDirectMemory 和 MaxHeapMemory

java - 使用 Spring-Social-Twitter Api inReplyToStatus 发推文不起作用