【问题标题】:How can I pin a byte array in Java?如何在 Java 中固定字节数组?
【发布时间】:2009-07-11 03:58:29
【问题描述】:

有没有办法在 java 中固定一个字节数组,所以它永远不会被移动/压缩?

我正在开发一个旨在在运行时实现零 GC 的应用程序,并且我想使用固定到内存映射区域的原始字节数组。有什么办法可以做到这一点或破解我的方法吗?

【问题讨论】:

  • 我可以问这个问题:为什么?为什么要在应用程序中不使用 GC,以及为什么要固定数组?
  • 我正在尝试将 RDMA 集成到我的流程中,并且希望获得尽可能好的性能。我不想在我的应用程序中使用 GC,因为我的应用程序对延迟非常敏感,它绝不能暂停,即使 3 毫秒也不行。我想要固定字节数组而不是直接字节缓冲区,因为字节数组访问性能比字节缓冲区好得多。

标签: java arrays memory-management garbage-collection


【解决方案1】:

您可以使用 ByteBuffer/allocateDirect() 这将创建一个字节缓冲区,该缓冲区位于“c”空间中并且不使用堆,因此它不会被移动并且可以在 JNI 调用中有效使用。

【讨论】:

  • 字节缓冲区的性能比字节数组差,所以我尽量避免使用它们。
  • 真的吗?而且我认为 ByteBuffer 的全部意义在于提高性能(至少对于某些操作);)要么你需要这个功能,要么你不需要。
  • Peter 是对的,直接 NIO 缓冲区用于许多 Java 绑定,通常是因为它们不会被移动并且适合 JNI 调用。
【解决方案2】:

真正的零垃圾回收?真的吗?

如果是这样,我会建议以下两种选择之一:

  1. 使用real-time JVM。几乎所有将通用应用程序从软实时系统到硬实时系统分开的东西都可以通过多种方式进行管理。
  2. 请认真考虑分配比您在特定运行期间所需的内存多得多的内存。这不是一个复杂的解决方案,但如果您有可用的内存,请尝试在核心占用空间中分配比您预期需要多 10 倍的内存。它可能会起作用,而且您必须承认,RAM 比软件工程劳动力便宜。

稍后再编辑:

我突然想到你应该考虑静态分配你的字节数组。即,像这样:

/** Byte arrays that you absolutely have to keep. */
public class KeepForever {
    /** Note that I make no claims about thread safety in this simple example. */
    public static byte [] keepMe = new byte[100];
};

// Much later in example code ....

/** This should always succeed.  No worries about garbage collection. */
public void setMe(int index, byte newByte) {
    // Admittedly, this defeats several principles of OOD but it makes 
    // the point about the syntax.
    KeepForever.keepMe[index] = newByte;
}

【讨论】:

  • 真正的零垃圾回收。我的应用程序在启动时分配所有内容,并且不再进行任何进一步的分配。但是,我认为不进行任何分配不能保证 JVM 不会运行 GC 并压缩我的堆,这是我所关心的。我不想使用实时 JVM,因为我想要高吞吐量和低延迟,而不是一致的中等延迟和平均吞吐量。
  • 预分配数组不会阻止它在垃圾收集期间被移动(假设有其他东西触发了 GC。)
【解决方案3】:

https://highlyscalable.wordpress.com/2012/02/02/direct-memory-access-in-java/。要在不使用反射或将代码绑定到特定 JVM 的情况下使用它,您需要创建一个长度和类型与现有数组相同的数组,或者创建非数组对象的浅表副本。

【讨论】:

    【解决方案4】:

    虽然它与直接内存映射无关,但仍可引用的对象不会被 GC。引用保持有效的任何内容都应该没问题。

    【讨论】:

    • 但是使用分代GC,它将被移动到内存中。
    【解决方案5】:

    JNI 支持一些“固定”,但它非常有限。它只能在 JNI 调用的上下文中发生,而不是在它们之间发生,并且不需要每个 JVM 实现都支持。

    GetPrimitiveArrayCritical 返回 Java™ 数组的直接堆地址,在调用相应的 ReleasePrimitiveArrayCritical 之前禁用垃圾收集。

    Copying and Pinning

    ...在调用 ReleasePrimitiveArrayCritical 之前,本机代码不应长时间运行。 ... 不得调用其他 JNI 函数,或任何可能导致当前线程阻塞并等待另一个 Java 线程的系统调用。

    ...即使 VM 不支持固定。

    GetPrimitiveArrayCritical

    对于您描述的使用共享内存的应用程序,您可能会考虑根本不使用 Java 数组,而是使用 JNI 来更直接地访问资源。

    【讨论】:

      猜你喜欢
      • 2015-11-11
      • 2016-05-14
      • 1970-01-01
      • 2022-11-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多