Java 中有没有办法让两个 JVM(在同一台物理机器上运行)使用/共享相同的内存地址空间?假设 JVM-1 中的生产者将消息放在特定的预定义内存位置,如果 JVM-2 上的消费者知道要查看哪个内存位置,它是否可以检索消息?
原文由 OneWorld 发布,翻译遵循 CC BY-SA 4.0 许可协议
Java 中有没有办法让两个 JVM(在同一台物理机器上运行)使用/共享相同的内存地址空间?假设 JVM-1 中的生产者将消息放在特定的预定义内存位置,如果 JVM-2 上的消费者知道要查看哪个内存位置,它是否可以检索消息?
原文由 OneWorld 发布,翻译遵循 CC BY-SA 4.0 许可协议
有一些 IPC 库可以通过 Java 中的内存映射文件促进共享内存的使用。
Chronicle Queue 类似于非阻塞 Java Queue
,除了你可以在一个 JVM 中提供一条消息并在另一个 JVM 中轮询它。
在这两个 JVM 中,您应该在同一 FS 目录中创建一个 ChronicleQueue
实例(如果不需要消息持久性,请将此目录放置在内存挂载的 FS 中):
ChronicleQueue ipc = ChronicleQueueBuilder.single("/dev/shm/queue-ipc").build();
在一个 JVM 中写一条消息:
ExcerptAppender appender = ipc.acquireAppender();
appender.writeDocument(w -> {
w.getValueOut().object(message);
});
在另一个 JVM 中读取消息:
ExcerptTailer tailer = ipc.createTailer();
// If there is no message, the lambda, passed to the readDocument()
// method is not called.
tailer.readDocument(w -> {
Message message = w.getValueIn().object(Message.class);
// process the message here
});
// or avoid using lambdas
try (DocumentContext dc = tailer.readingDocument()) {
if (dc.isPresent()) {
Message message = dc.wire().getValueIn().object(Message.class);
// process the message here
} else {
// no message
}
}
Aeron 不仅仅是 IPC 队列(它是一个网络通信框架),它还提供了 IPC 功能。它类似于 Chronicle Queue,一个重要区别是它使用 SBE 库进行消息编组/解组,而 Chronicle Queue 使用 Chronicle Wire 。
Chronicle Map 允许通过一些密钥进行 IPC 通信。在这两个 JVM 中,您应该创建一个具有相同配置的映射并持久保存到同一个文件(如果您不需要实际的磁盘持久性,该文件应该位于内存挂载的 FS 中,例如 /dev/shm/
):
Map<Key, Message> ipc = ChronicleMap
.of(Key.class, Message.class)
.averageKey(...).averageValue(...).entries(...)
.createPersistedTo(new File("/dev/shm/jvm-ipc.dat"));
然后在一个 JVM 中你可以这样写:
ipc.put(key, message); // publish a message
在接收者 JVM 上:
Message message = ipc.remove(key);
if (message != null) {
// process the message here
}
原文由 leventov 发布,翻译遵循 CC BY-SA 3.0 许可协议
3 回答2.7k 阅读✓ 已解决
3 回答4.1k 阅读✓ 已解决
8 回答3.8k 阅读
4 回答2.8k 阅读✓ 已解决
2 回答2.7k 阅读✓ 已解决
3 回答2.6k 阅读✓ 已解决
4 回答1.9k 阅读
解决方案 1:
我认为最好的解决方案是使用内存映射文件。这允许您在任意数量的进程(包括其他非 Java 程序)之间共享内存区域。除非序列化它们,否则不能将 java 对象放入内存映射文件中。以下示例显示您可以在两个不同的进程之间进行通信,但是您需要使其更加复杂以允许进程之间更好的通信。我建议你看看 Java 的 NIO 包,特别是下面示例中使用的类和方法。
服务器:
客户:
解决方案 2:
另一种解决方案是使用 Java Sockets 在进程之间来回通信。这具有允许非常容易地通过网络进行通信的额外好处。可以说这比使用内存映射文件慢,但我没有任何基准来支持该声明。我不会发布实现此解决方案的代码,因为实现可靠的网络协议会变得非常复杂,并且相当特定于应用程序。可以通过快速搜索找到许多不错的社交网站。
现在上面的例子是如果你想在两个不同的进程之间共享内存。如果您只想在当前进程中读取/写入任意内存,您应该首先了解一些警告。这违背了 JVM 的整个原则,你真的不应该在生产代码中这样做。您违反了所有安全规定,如果您不小心,很容易使 JVM 崩溃。
话虽如此,尝试它还是很有趣的。要读取/写入当前进程中的任意内存,您可以使用
sun.misc.Unsafe
类。这在我知道并使用过的所有 JVM 上都提供。可以在 此处 找到有关如何使用该类的示例。