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
}
}
public static Unsafe getUnsafe() {
try {
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
return (Unsafe)f.get(null);
} catch (Exception e) { /* ... */ }
}
MyStructure structure = new MyStructure(); // create a test object
structure.x = 777;
long size = sizeOf(structure);
long offheapPointer = getUnsafe().allocateMemory(size);
getUnsafe().copyMemory(
structure, // source object
0, // source offset is zero - copy an entire object
null, // destination is specified by absolute address, so destination object is null
offheapPointer, // destination address
size
); // test object was copied to off-heap
Pointer p = new Pointer(); // Pointer is just a handler that stores address of some object
long pointerOffset = getUnsafe().objectFieldOffset(Pointer.class.getDeclaredField("pointer"));
getUnsafe().putLong(p, pointerOffset, offheapPointer); // set pointer to off-heap copy of the test object
structure.x = 222; // rewrite x value in the original object
System.out.println( ((MyStructure)p.pointer).x ); // prints 777
....
class Pointer {
Object pointer;
}
所以现在你通过了 MyStructure 以及 p 从((mystructure)p.pointer).x到第二个jvm,您应该能够:
7条答案
按热度按时间gj3fmq9x1#
分布式缓存是满足您需求的最佳解决方案。
在计算中,分布式缓存是传统缓存概念在单一区域中的扩展。分布式缓存可以跨越多个服务器,这样它的大小和容量就可以增加。
选项很少:
terracotta允许jvm集群中的线程跨jvm边界进行交互,使用相同的内置jvm设施扩展到集群范围
oracle\u coherence是一个基于java的内存数据网格,它比传统的关系数据库管理系统具有更好的可靠性、可扩展性和性能
ehcache是一种广泛使用的开源java分布式缓存,用于通用缓存、javaee和轻量级容器。它具有内存和磁盘存储、按拷贝复制和失效、侦听器、缓存加载程序、缓存扩展、缓存异常处理程序、gzip缓存servlet过滤器、restful和soapis
redis是一个数据结构服务器。它是开源的、网络化的、内存中的,并且存储的密钥具有可选的耐久性。
couchbase\u服务器是一个开源的、分布式(无共享体系结构)的多模型nosql面向文档的数据库软件包,它针对交互式应用程序进行了优化。这些应用程序可以通过创建、存储、检索、聚合、操作和呈现数据来服务于许多并发用户。
有用的帖子:
什么是陶土?
terracotta是分布式缓存吗?
infoq文章
uxh89sit2#
老实说,你不想分享同样的记忆。您应该只将需要的数据发送到另一个jvm。也就是说,如果您确实需要共享内存,那么就存在其他解决方案。
两个jvm不共享相同的内存访问点,因此不可能使用一个jvm的引用来在另一个jvm中使用。只需创建一个新的引用,因为他们彼此不了解。
但是,您可以将数据发送到其他jvm,然后以各种方式返回:
1) 使用rmi,您可以设置一个远程服务器来解析数据。我发现设置起来有点麻烦,因为它需要更改安全性,而且数据
Serializable
. 你可以在链接上找到更多信息。2) 使用服务器是将数据发送到不同地方的古老方法。实现这一点的一种方法是使用
ServerSocket
和一个Socket
在localhost
. 对象仍然需要Serializable
如果你想用ObjectOutputStream
.共享数据这是非常危险和不稳定的,低级别的,以及,嗯,不安全的(字面意思)。
如果您想使用java代码,可以看看
s.m.Unsafe
,使用正确的内存地址,您将能够检索操作系统中备份c/c数组存储的对象。否则,您可以使用
native
方法来访问c/c数组,尽管我不知道如何实现。eeq64g8w3#
解决方案1:
在我看来,最好的解决方案是使用内存Map文件。这允许您在任意数量的进程(包括其他非java程序)之间共享一个内存区域。不能将java对象放入内存Map文件中,除非序列化它们。下面的示例显示您可以在两个不同的进程之间进行通信,但是您需要使其更加复杂,以便在进程之间进行更好的通信。我建议您看看java的nio包,特别是下面示例中使用的类和方法。
服务器:
客户:
解决方案2:
另一种解决方案是使用javasockets在进程之间来回通信。这样做还有一个额外的好处,就是可以很容易地通过网络进行通信。可以说,这比使用内存Map文件慢,但我没有任何基准来支持该语句。我不会发布代码来实现这个解决方案,因为实现一个可靠的网络协议可能会变得非常复杂,而且是相当特定于应用程序的。有许多好的网络站点可以通过快速搜索找到。
如果您想在两个不同的进程之间共享内存,那么上面的例子就是。如果您只想在当前进程中读/写任意内存,那么应该首先知道一些警告。这违背了jvm的整个原则,您真的不应该在生产代码中这样做。你违反了所有的安全性,如果你不小心的话很容易使jvm崩溃。
尽管如此,这是相当有趣的实验。要在当前进程中读取/写入任意内存,可以使用
sun.misc.Unsafe
班级。我知道并使用过的所有jvm都提供了这个功能。关于如何使用这个类的例子可以在这里找到。ia2d9nvy4#
有一些ipc库通过java中的内存Map文件来促进共享内存的使用。
历史记录队列
编年史队列类似于非阻塞java
Queue
,但您可以在一个jvm中提供消息,并在另一个jvm中轮询它。在这两个JVM中,您应该创建一个
ChronicleQueue
同一fs目录中的示例(如果不需要消息持久性,请在内存装载的fs中找到此目录):在一个jvm中编写消息:
在另一个jvm中读取消息:
aeron ipc公司
aeron不仅仅是ipc队列(它是一个网络通信框架),它还提供了ipc功能。它类似于chronicle queue,一个重要的区别是它使用sbe库进行消息编组/解编组,而chronicle queue使用chronicle wire。
编年史Map
编年史Map允许ipc通过一些键进行通信。在这两个JVM中,您应该创建一个具有相同配置的Map,并将其持久化到同一个文件(如果您不需要实际的磁盘持久化,则该文件应该在内存挂载的fs中进行本地化,例如。g。在
/dev/shm/
):然后在一个jvm中可以编写:
在接收器jvm上:
xdyibdwo5#
乔凯特,我几年前做的一个实验项目就是这样做的。
它包括替换
java.net.Socket
以及java.net.ServerSocket
如果你想用Input/OutputStream
.每个定向通道使用一对循环缓冲区来发布和获取数据(一个用于“数据包”,一个用于数据包地址)。缓冲器是通过
RandomAccessFile
.它包括一个小的jni层(linux)来实现ipc同步(即通知其他进程数据的可用性),但是如果您想轮询数据,这不是必需的。
li9yvcax6#
pivot堆外内存不安全
如何使用不安全的方法将对象字节复制到非头部区域,然后将廉价的指针和类名传递给第二个jvm,该jvm将使用指针和类名将堆外空间复制并强制转换到第二个jvm中的堆内对象。它不是同一个对象示例,而是一个快速拷贝,没有序列化。
所以现在你通过了
MyStructure
以及p
从((mystructure)p.pointer).x到第二个jvm,您应该能够:我可以想象一个用例:假设你有两个微服务,它们可能在同一台服务器上运行,也可能不在同一台服务器上运行,还有一个客户端策略,可能在容器appserver中实现,它知道服务部署在何处,以防它检测到请求的服务在本地,它可能使用基于不安全的服务客户机透明地查询其他服务。讨厌但有趣的是,我想看看不使用网络、绕过webapi(直接调用处理控制器)和不序列化对性能的影响。在这种情况下,除了控制器参数外,还应提供控制器本身。根本没想过安全问题。
借用的代码段https://highlyscalable.wordpress.com/2012/02/02/direct-memory-access-in-java/
umuewwlo7#
对,
使用中间程序,您可以写入和读取任意内存位置。你不能完全用java来做。
例如,您可以编写一段可以读取任意内存位置的c++代码,并通过jni调用它。同样的情况反过来也适用于写入内存地址。
首先为应处理此问题的类编写类定义,例如:
然后你编译它。然后使用javah.exe(或等效的linux)为其生成标头:
现在编写一个.cpp文件,其中包含该头并定义方法。编译到dll。要加载.dll,可以使用-djava.library.path jvm参数和适当的值,也可以使用system.loadlibrary()。
注意:我不建议这样做。几乎可以肯定有更好的方法来做你想做的事。