首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >缓冲区与不安全-外部JVM

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

Stack Overflow用户
提问于 2015-12-26 08:00:49
回答 1查看 2.2K关注 0票数 2

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

代码语言:javascript
复制
package com.directmemory;

进口java.lang.reflect.Field;进口java.nio.ByteBuffer;

进口sun.misc.Unsafe;

公共类DirectMemoryTest {

代码语言:javascript
复制
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的缓冲区?因此,如果我的要求是存储3GB的数据,那么我必须创建一个新的缓冲区并将数据存储在那里,这意味着除了存储数据之外,我还有额外的责任来标识各自的缓冲区(从“n”缓冲区列表中),该缓冲区维护一个指向直接内存的指针。

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

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

4)为什么最后的sysout语句没有得到0.0?其思想是,每双使用8个字节,所以我将1.0at地址存储在由allocateMemory say address = 1返回的地址,2.0at address 1+8,即9,然后停止。那么,默认值不是应该是0.0吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-12-26 10:09:57

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

1)如果您的代码必须在Java8到Java10(及更高版本)中不改变地运行,那么使用ByteBuffers的方法1是可行的。

如果您准备用Java9/ Java 10中的任何替换替换sun.misc.Unsafe的使用,那么您很可能会使用sun.misc.Unsafe。

2)对于大于2 GBytes的大型数据结构,方法2可能会更快,因为在方法1中需要额外的间接指向。然而,如果没有一个可靠的(微观)基准,我将不会对它下任何赌注。

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

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

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

4b)在分配的内存之外读取16个字节,这将导致JVM崩溃(取决于处理器体系结构和操作系统以及以前的内存使用情况)。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34469568

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档