【问题标题】:What is the purpose to use direct memory in Java?在 Java 中使用直接内存的目的是什么?
【发布时间】:2019-03-17 02:25:36
【问题描述】:

从 java 1.4 开始引入了直接内存。新的 I/O (NIO) 类引入了一种基于通道和缓冲区执行 I/O 的新方法。 NIO 增加了对直接 ByteBuffers 的支持,它可以直接传递到本机内存而不是 Java 堆。在某些情况下使它们显着加快,因为它们可以避免在 Java 堆和本机堆之间复制数据。

我一直不明白我们为什么要使用直接记忆。谁能帮忙举个例子?

【问题讨论】:

  • 为了性能?
  • 我的一个例子是,当您需要将顶点数据传递给 GPU 时,它们非常适合与 LWJGL、IIRC 一起使用,您将其存储在直接缓冲区中,这样您就可以轻松地管道输入数据而无需从类中解码。
  • “在某些情况下明显更快”还不够合理吗?

标签: java jvm


【解决方案1】:

我一直不明白我们为什么要使用直接记忆。谁能帮忙举个例子?

所有系统调用,例如读写套接字和文件,都只使用本机内存。他们不能使用堆。这意味着虽然您可以从堆中复制到本机内存或从本机内存复制,但避免这种复制可以提高效率。

我们使用堆外/本机内存来存储我们的大部分数据,这有很多优势。

  • 它可以大于堆大小。
  • 它可以大于主内存。
  • 它可以在 JVM 之间共享。即多个 JVM 的一份副本。
  • 它可以在 JVM 甚至机器重新启动时持久化和保留。
  • 它对 GC 暂停时间几乎没有影响。
  • 根据使用情况可能会更快

它没有被更多使用的原因是它更难使它既高效又像普通 Java 对象一样工作。出于这个原因,我们有诸如Chronicle Map 之类的库,它充当ConcurrentMap,但使用堆外内存,以及Chronicle Queue,它是一个日志、记录器和进程之间的持久IPC。

【讨论】:

    【解决方案2】:

    JVM 依靠垃圾收集的概念来回收不再使用的内存。这使得 JVM 语言开发人员(例如 Java、Scala 等)不必担心内存分配和释放。您只需请求内存,让 JVM 担心它何时会被回收或垃圾收集。

    虽然这非常方便,但它会增加单独线程的开销,消耗 CPU 并且必须不断地通过 JVM 堆,回收不再可访问的对象。有关该主题的整本书都写了,但是如果您想阅读更多有关 JVM 垃圾收集的信息,那里有大量的参考资料,但是这本很不错:https://dzone.com/articles/understanding-the-java-memory-model-and-the-garbag

    无论如何,如果在您的应用程序中,您知道您将进行大量复制、更新对象和值,您可以选择自己处理这些对象及其内存消耗。因此,无论这些对象中有多少流失,这些对象永远不会在堆中移动,它们永远不会被垃圾收集,因此不会影响 JVM 中的垃圾收集。这个答案有更多细节:https://stackoverflow.com/a/6091680/236528

    来自官方 Javadoc:

    直接与非直接缓冲区

    字节缓冲区可以是直接的,也可以是非直接的。给定一个直接字节 缓冲区,Java 虚拟机将尽最大努力执行 直接对其进行本地 I/O 操作。也就是说,它将尝试 避免将缓冲区的内容复制到(或从)中间缓冲区 在每次调用基础操作之一之前(或之后) 系统的本机 I/O 操作。

    直接字节缓冲区可以通过调用allocateDirect来创建 这个类的工厂方法。此方法返回的缓冲区 分配和解除分配的成本通常比 非直接缓冲区。 直接缓冲区的内容可能驻留在 在正常的垃圾收集堆之外,因此它们对 应用程序的内存占用可能并不明显。 因此建议将直接缓冲区主要分配给 受底层系统影响的大型、长寿命缓冲区 本机 I/O 操作。 一般来说最好直接分配 仅当它们在程序中产生可测量的增益时才缓冲 性能。

    https://download.java.net/java/early_access/jdk11/docs/api/java.base/java/nio/ByteBuffer.html

    【讨论】:

    • 引用的部分只是说直接缓冲区“可能驻留在正常的垃圾收集堆之外”,但从未声称这会对垃圾收集器的性能产生积极影响。事实上,它说他们可能有“更高的分配和解除分配成本”。由于任何认真的 JVM 都知道在 byte[] 数组中没有对象引用,因此在垃圾收集方面,直接缓冲区和非直接缓冲区之间没有显着差异。当本机代码想要访问内存时,差异就会发挥作用,这是一个完全不同的话题。
    猜你喜欢
    • 2011-04-12
    • 1970-01-01
    • 2017-11-25
    • 2020-01-05
    • 2020-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-18
    相关资源
    最近更新 更多