首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >两个JVM之间的共享内存

两个JVM之间的共享内存
EN

Stack Overflow用户
提问于 2014-08-20 04:20:06
回答 7查看 54.9K关注 0票数 47

对于两个JVM(运行在同一台物理机器上),Java中是否有一种使用/共享相同内存地址空间的方法?假设JVM-1中的生产者将消息放置在特定的预定义内存位置,如果JVM-2上的使用者知道要查看哪个内存位置,它能检索消息吗?

EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2014-08-20 05:25:26

解决方案1:

在我看来,最好的解决方案是使用内存映射文件。这允许您在任意数量的进程之间共享内存区域,包括其他非java程序。除非序列化java对象,否则不能将它们放置到内存映射文件中。下面的示例显示,您可以在两个不同的进程之间进行通信,但是您需要使其更加复杂,以便在进程之间进行更好的通信。我建议您查看一下Java的NIO封装,特别是下面示例中使用的类和方法。

服务器:

代码语言:javascript
运行
复制
public class Server {

    public static void main( String[] args ) throws Throwable {
        File f = new File( FILE_NAME );

        FileChannel channel = FileChannel.open( f.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE );

        MappedByteBuffer b = channel.map( MapMode.READ_WRITE, 0, 4096 );
        CharBuffer charBuf = b.asCharBuffer();

        char[] string = "Hello client\0".toCharArray();
        charBuf.put( string );

        System.out.println( "Waiting for client." );
        while( charBuf.get( 0 ) != '\0' );
        System.out.println( "Finished waiting." );
    }
}

客户端:

代码语言:javascript
运行
复制
public class Client {

    public static void main( String[] args ) throws Throwable {
        File f = new File( FILE_NAME );
        FileChannel channel = FileChannel.open( f.toPath(), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE );

        MappedByteBuffer b = channel.map( MapMode.READ_WRITE, 0, 4096 );
        CharBuffer charBuf = b.asCharBuffer();

        // Prints 'Hello server'
        char c;
        while( ( c = charBuf.get() ) != 0 ) {
            System.out.print( c );
        }
        System.out.println();

        charBuf.put( 0, '\0' );
    }

}

解决方案2:

另一种解决方案是使用Java 插座在进程之间来回通信。这有一个额外的好处,就是可以很容易地在网络上进行通信。可以说,这比使用内存映射文件要慢,但我没有任何基准来支持该语句。我不会发布代码来实现这个解决方案,因为实现一个可靠的网络协议会变得非常复杂,并且是相当特定于应用程序的。有许多好的网站,可以找到快速搜索。

现在,如果您想在两个不同的进程之间共享内存,那么上面的示例就是。如果您只想在当前进程中读取/写入任意内存,那么首先应该知道一些警告。这违反了JVM的整个原则,您真的不应该在生产代码中这样做。如果不小心,您就会破坏所有的安全,并且很容易使JVM崩溃。

尽管如此,这是相当有趣的实验。要在当前进程中对任意内存进行读写,可以使用sun.misc.Unsafe类。这是在我所知道和使用过的所有JVM上提供的。有关如何使用该类的示例可以找到这里

票数 38
EN

Stack Overflow用户

发布于 2016-07-10 09:41:03

有一些IPC库可以通过Java中的内存映射文件来方便共享内存的使用.

纪事队列

Chronicle类似于一个非阻塞的Queue,但您可以在一个JVM中提供消息,然后在另一个JVM中轮询它。

在这两个JVM中,您应该在同一个FS目录中创建一个ChronicleQueue实例(如果不需要消息持久性,请在内存挂载的FS中找到这个目录):

代码语言:javascript
运行
复制
ChronicleQueue ipc = ChronicleQueueBuilder.single("/dev/shm/queue-ipc").build();

在一个JVM中编写一条消息:

代码语言:javascript
运行
复制
ExcerptAppender appender = ipc.acquireAppender();
appender.writeDocument(w -> {
    w.getValueOut().object(message);
});

读取另一个JVM中的消息:

代码语言:javascript
运行
复制
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
    }
}

副翼IPC

副翼不仅仅是IPC队列(它是一个网络通信框架),但它也提供了IPC功能。它类似于纪事队列,一个重要的区别是它使用SBE库来进行消息编组/脱卸,而纪事队列使用纪事线材

纪事图

Chronicle允许IPC通过某些键进行通信。在这两个JVM中,您应该创建一个配置相同的映射,并将其持久化到同一个文件(如果您不需要实际的磁盘持久化(例如,在/dev/shm/中),那么文件应该定位在内存挂载的FS中):

代码语言:javascript
运行
复制
Map<Key, Message> ipc = ChronicleMap
    .of(Key.class, Message.class)
    .averageKey(...).averageValue(...).entries(...)
    .createPersistedTo(new File("/dev/shm/jvm-ipc.dat"));

然后,在一个JVM中您可以编写:

代码语言:javascript
运行
复制
ipc.put(key, message); // publish a message

在接收JVM上:

代码语言:javascript
运行
复制
Message message = ipc.remove(key);
if (message != null) {
    // process the message here
}
票数 30
EN

Stack Overflow用户

发布于 2016-07-10 10:06:46

缓存是解决需求的最佳解决方案。

在计算中,分布式缓存是传统缓存概念在单个区域中使用的扩展。分布式缓存可以跨越多个服务器,从而使其在大小和跨国容量上都能增长。

没有几种选择:

兵马俑允许JVM集群中的线程通过JVM边界相互交互,使用相同的内置JVM设施扩展为具有集群范围的含义。

一致性是一种专有的基于1Java的内存数据网格,与传统的关系数据库管理系统相比,它具有更好的可靠性、可扩展性和性能。

Ehcache是一个广泛使用的开源,用于通用缓存、Java和轻量级容器。它具有内存和磁盘存储、复制和无效复制、侦听器、缓存加载器、缓存扩展、缓存异常处理程序、gzip缓存servlet筛选器、RESTful和SOAP APIs。

Redis是一种数据结构服务器。它是开源的,联网的,内存中的,并且存储具有可选持久性的密钥.

服务器是一个开放源码、分布式(无共享架构)的面向NoSQL文档的多模型数据库软件包,是针对交互式应用程序进行优化的。这些应用程序可以通过创建、存储、检索、聚合、操作和显示数据为许多并发用户服务。

有用的员额:

什么是兵马俑?

Terracotta是分布式缓存吗?

信息Q文章

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

https://stackoverflow.com/questions/25396664

复制
相关文章

相似问题

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