ArangoDB 将所有数据存储在内存映射文件中。每个集合可以有 0 到 n 个数据文件,每个默认文件大小为 32 MB(请注意,此文件大小可以全局调整或在每个集合级别上调整)。空集合(从未有任何数据)将没有数据文件。对集合的第一次写入将创建数据文件,并且每当数据文件已满时,将自动创建一个新的。
默认情况下,集合以 32 MB 的块分配数据文件。如果您确实有很多但很小的集合,这可能会浪费一些内存。如果你有很多很少但很大的集合,那么潜在的浪费(数据文件末尾的可用空间)可能并不重要。
每当任何 ArangoDB 操作从内存映射数据文件读取数据或将数据写入内存映射数据文件时,操作系统都会首先将文件中的偏移量转换为页码。这是因为每个数据文件都被隐式分割成特定大小的页面。页面大小取决于平台,但我们假设页面大小为 4 KB。因此,具有默认文件大小的数据文件将有 8192 页。
操作系统将文件中的偏移量转换为页码后,它会确保请求页的数据存在于物理 RAM 中。如果页面尚未在物理 RAM 中,操作系统将发出页面错误以触发从磁盘加载请求的页面或交换到物理 RAM。这最终将使整个页面在 RAM 中可用,之后可能会发生对该页面数据的任何读取或写入。
所有这些都是由操作系统的虚拟内存管理器完成的。操作系统可以自由地将数据文件中的尽可能多的页面映射到 RAM 中,只要它认为是好的。例如,当一个内存映射文件被顺序访问时,操作系统可能会很聪明并且预读很多页,因此在实际访问时它们已经在物理 RAM 中。
操作系统也可以自由地换出数据文件的部分或全部页面。如果没有足够的物理 RAM 可以同时将所有数据文件的所有页面保存在 RAM 中,它可能会换出页面。它还可以换出一段时间未使用的页面,以使 RAM 可用于其他操作。它可能会为此使用一些 LRU 算法。
操作系统的虚拟内存管理器的行为方式在平台和实现之间存在很大差异。大多数系统还允许配置 VM 子系统。例如,这里有一些 Linux 的 VM 子系统的参数。
因此,很难判断 ArangoDB 实际将多少物理内存用于给定数量的集合及其数据文件。如果根本不访问集合,则将数据文件进行内存映射可能几乎不使用 RAM,因为操作系统可能已完全或至少部分交换了集合。如果这些集合被大量使用,操作系统可能会将它们的数据文件完全映射到 RAM 中。但在这两种情况下,内存都算作内存映射。这是您可以拥有比物理 RAM 更高的虚拟内存使用量。
如前所述,操作系统在访问不在 RAM 中的页面时必须做很多工作,如果可能的话,您希望避免这种情况。如果您经常使用的集合的总大小超过物理 RAM 的大小,则操作系统别无选择,只能在您访问这些集合时大量交换页面。使用 SSD 进行交换可能比使用旋转 HDD 更好,但仍然比 RAM 访问慢得多。长话短说:如果可能,您的活动集合(数据文件和索引)的数据应该适合物理 RAM,否则您将看到大量磁盘活动。
除此之外,ArangoDB 不仅为集合数据文件分配虚拟内存,而且还启动了一些也使用虚拟内存的 V8 线程(V8 是 ArangoDB 中的 JavaScript 引擎)。此虚拟内存不是文件支持的。
在一个空的 ArangoDB V8 中占了大部分虚拟内存使用量。例如,在我的 64 位计算机上,V8 线程消耗大约 5 GB 的虚拟内存(但 ArangoDB 总共只使用 140 MB RAM),而在我的 RAM 较少的 32 位计算机上,V8 线程使用大约 600 - 700 MB虚拟内存。在您的情况下,使用 4.5 GB 的 VM,我怀疑 V8 也是原因。
V8 线程的虚拟内存使用量显然与启动的 V8 线程数相关。例如,增大启动参数 --server.threads 的值会启动更多的线程并使用更多的 V8 虚拟内存,而降低该值将启动更少的线程并使用更少的虚拟内存。