【问题标题】:moving objects off heap将对象移出堆
【发布时间】:2014-10-05 02:45:48
【问题描述】:

有没有人尝试将 java 对象移出堆?我尝试通过使用 Unsafe 库来使用序列化、反序列化和存储字节数组。但是其中包含多个对象的复杂对象使这是一个乏味的过程。有更好的解决方案吗?

【问题讨论】:

  • 你想做什么?也许各种数据库系统之一可以工作?
  • “移出堆”是什么意思?
  • 如果您有复杂的映射,我建议您坚持使用 Java 序列化本身,您可以使用 JDBC 存储对象状态,例如使用 hibernate,但这需要完成复杂的映射,这将使您的情况更加复杂。
  • 你研究过 apache directmemory 吗? directmemory.apache.org 或 mapdb.org
  • 我查看了 Apache Direct 内存。我正在研究更多从 Java 程序访问磁盘空间,例如 C 指针并执行“复杂对象数组”操作

标签: java unsafe


【解决方案1】:

unsafe 字段是您的 Unsafe 实例。如果您不知道如何获取它,只需使用:

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

    return null;
}

请记住,这应该适用于 HotSpot JVM,因为字段名称在不同的实现中有所不同。

您可以通过以下方式将对象移出堆:

1) 为内存地址分配适当的字节。您可以在偏移量 4L 处读取 int,转换为 unsigned long,然后添加 12L,并获取该位置的地址。

一个示例实现:

public static long sizeOf(Object object) {
    return unsafe.getAddress( normalize( unsafe.getInt(object, 4L) ) + 12L );
}

public static long normalize(int value) {
   if(value >= 0) return value;
   return (~0L >>> 32) & value;
}

您可以使用以下方法分配堆外空间:

Object object = // Your object
long size = sizeOf(object);
long address = unsafe.allocateMemory(size);

(保持地址字段方便)

2) 将对象复制到地址指定的内存段中。

例子:

getUnsafe().copyMemory(
            object,
            0,
            null,
            address,
            size);

完成!现在你的对象是堆外对象。

要取回您的对象,只需执行以下操作:

// Class wide field
Object anchor;

// Deserializarion
long offset = unsafe.objectFieldOffset(this.getClass().getDeclaredField("anchor"));

unsafe.putLong(this, offset, address);

那么,anchor 应该是你的堆外对象!

注意:请记住在完成以下操作时释放已分配内存的资源:

unsafe.freeMemory(address);

(看,告诉过你地址很重要[好像还不是很明显])

来源:http://highlyscalable.wordpress.com/2012/02/02/direct-memory-access-in-java/,一位名叫 RawCode 的好人,我不相信他在这里,但不久前告诉我 Unsafe 的工作原理。

【讨论】:

  • 谢谢 Dudex。我以前见过这个,我很不明白“return unsafe.getAddress(normalize(unsafe.getInt(object, 4L)) + 12L);”部分。
  • 读取代表对象大小的数字在其标头hg.openjdk.java.net/jdk7u/jdk7u60/hotspot/file/ba66650acf63/src/…
  • 我试图在序列化后为字节流分配内存,然后检索反序列化和读取。但我无法以这种方式正确分配内存...... byte[] abc = ser.serialize(ex); // ex 是一个有两个 int 和一个 string 的对象 size = abc.length;地址 = unsafe.allocateMemory(size); unsafe.putObject(abc, 地址, abc);
  • 我认为最好开一个新问题。
【解决方案2】:

有一些库使这个过程至少不那么大惊小怪,最多存储和更多对象更有效地进出堆外内存。我首先想到了Chronicle Values 和Slab,但我记得还有更多。

【讨论】:

    猜你喜欢
    • 2018-11-18
    • 1970-01-01
    • 2017-11-07
    • 2018-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多