gpt4 book ai didi

java - Neo4j对象缓存的理解

转载 作者:行者123 更新时间:2023-11-30 08:20:51 27 4
gpt4 key购买 nike

我试图通过一些调查来了解 Neo4j 对象缓存。我对对象缓存的第一印象来自这个链接中的幻灯片: http://www.slideshare.net/thobe/an-overview-of-neo4j-internals

具体来说,缓存中的节点/关系对象应该类似于幻灯片 9 或 15/42。为了验证这一点,我使用现有的图形数据库内容编写了一个简单的服务器脚本。我这样做的方法是尝试使用 sun.misc.Unsafe 查看节点/关系对象的起始虚拟地址。获取虚拟地址的程序来自以下链接: How can I get the memory location of a object in java?

public static long addressOf(Object o) throws Exception {
Object[] array = new Object[] { o };

long baseOffset = unsafe.arrayBaseOffset(Object[].class);
int addressSize = unsafe.addressSize();
long objectAddress;
switch (addressSize) {
case 4:
objectAddress = unsafe.getInt(array, baseOffset);
break;
case 8:
objectAddress = unsafe.getLong(array, baseOffset);
break;
default:
throw new Error("unsupported address size: " + addressSize);
}
return (objectAddress);
}

并且在 neo4j 服务器脚本(我的 main() 类)中,我通过 id 获取节点地址并按以下方式打印出地址:

void checkAddr(){
nodeAddr(0);
nodeAddr(1);
nodeAddr(2);
}

void nodeAddr(int n){
Node oneNode = graphDb.getNodeById(n);
Node[] array1 = {oneNode};

try {
long address = UnsafeUtil.addressOf(array1);
System.out.println("Addess: " + address);
} catch (Exception e) {
e.printStackTrace();
}
}

首先,我尝试使用软缓存提供程序,这是默认情况。为节点对象 0、1 和 2 打印出的地址是:

Addess: 4168500044 Addess: 4168502383 Addess: 4168502753

因此,使用第二个地址 - 第一个地址和第三个地址 - 第二个地址,我可以确切地知道节点占用了多少空间。在这种情况下,第一个节点对象占用 2339B,第二个占用 370B。

然后,为了查看禁用对象缓存的影响,我使用 NoCacheProvider 进行了设置:

setConfig(GraphDatabaseSettings.cache_type,NoCacheProvider.NAME)

打印出来的地址是:

Addess: 4168488391 Addess: 4168490708 Addess: 4168491056

与第一种情况类似计算的偏移量是:第一个节点对象占用 2317B,第二个占用 348B。

我的问题来了:

  1. 既然我使用同一个图并进行只读查询,为什么同一个节点对象的大小会发生变化?

  2. 当我禁用对象缓存时,为什么地址偏移量看起来与存在对象缓存一样?比如在node store文件中,单个节点占用9个字节,我的实验不是这样的。如果我获取节点对象的方式有问题,我怎样才能以正确的方式获取虚拟地址?有什么方法可以具体知道 mmap 节点文件驻留在内存中的什么位置?

  3. 我怎么才能准确知道节点对象中存储的内容。当我在这个链接上查看 Node.class 时: https://github.com/neo4j/neo4j/blob/1.9.8/community/kernel/src/main/java/org/neo4j/graphdb/Node.java节点对象看起来不应该与演示幻灯片中的一样。而只是节点对象使用的一组函数。另外,在没有对象缓存和有对象缓存的情况下,一个节点对象是否同时作为一个整体进入内存?

最佳答案

Node 对象不是 Neo4j 存储在“对象缓存”中的对象,因此您不会通过查看这些实例来深入了解 Neo4j 的缓存。 Neo4j 为您提供的 Node 的实现是名为 NodeProxy 的类的实例。 ,并且尽可能小(两个字段:内部 ID 和对数据库的引用)。这些只是作为节点的句柄,用于在数据库中围绕该节点执行操作。存储在“对象缓存”中的对象是名为 NodeImpl 的类的实例。 (尽管有名称,但它们并未实现 Node 接口(interface))。 NodeImpl 对象具有该演示文稿中第 15 张幻灯片(幻灯片中的第 9 页)中概述的形状。好吧,它大致具有那种形状,自从我制作这些幻灯片以来,Neo4j 已经发展。

Neo4j 的发展也改变了节点记录在磁盘上占用的字节数。 Neo4j 2.0 及更高版本的节点记录比那些幻灯片显示的节点记录稍大。如果您有兴趣查看这些记录的布局,您应该查看 NodeRecord类,然后从NodeStore开始类并“向下”进入其依赖项以找到内存映射。

除了查看错误的对象以了解 Neo4j 中不同缓存方法之间的差异之外,您的测量方法是有缺陷的。比较对象的地址并不能告诉您有关这些对象大小的任何信息。 JVM 不保证一个接一个(及时)分配的两个对象将在内存中相邻驻留,即使 JVM 确实使用了这样的分配策略,Neo4j 也可能在您分配的两个对象之间分配了多个对象正在比较。然后是垃圾收集器,它可能会在您获取一个对象的地址和获取下一个对象的地址之间移动对象。因此,在 Java 中查看对象的地址几乎没有任何用处。要想更好地测量 Java 中对象的大小,请查看 Java Object Layout utility。 ,或使用 Instrumentation.getObjectSize(...) method来自 Java 代理。

按照说明回答您的问题:

  1. 节点对象的大小没有变化,它们的地址不能保证在两次运行之间相同。根据我上面的描述,您不能依赖对象地址来计算对象大小。

  2. 由于您正在查看 NodeProxy 对象,因此无论 Neo4j 使用何种缓存策略,它们看起来都是一样的。为了查看 NodeImpl 对象,您必须深入挖掘 Neo4j 的内部结构。由于看起来您正在使用 Neo4j 1.9,因此您可以将 GraphDatabaseService 实例强制转换为 GraphDatabaseAPI(实现内部的接口(interface)),然后调用 该对象上的 getNodeManager() 方法。在 NodeManager 中,您可以调用 getNodeIfCached( node.getId() ) 来获取 NodeImpl 对象。请注意,此 API 在 Neo4j 的不同版本之间不兼容,使用它是一种“如果密封破损则保修无效”的情况......

  3. 改为查看 NodeImpl 的源代码。至于何时以及如何将数据放入缓存,Neo4j 尽量做到偷懒,只加载您使用的数据。如果您正在获取节点的关系,这些将被加载到缓存中,如果您正在获取属性,这些将被加载到缓存中。如果您只获取关系,则永远不会加载属性,反之亦然。

关于java - Neo4j对象缓存的理解,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25612552/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com