Tag: memory mapped files

Java MemoryMapping大文件

MappedByteBuffer对2GIG的Java限制使得用于映射大文件变得棘手。 通常推荐的方法是使用MappedByteBuffer数组并通过以下方式对其进行索引: long PAGE_SIZE = Integer.MAX_VALUE; MappedByteBuffer[] buffers; private int getPage(long offset) { return (int) (offset / PAGE_SIZE) } private int getIndex(long offset) { return (int) (offset % PAGE_SIZE); } public byte get(long offset) { return buffers[getPage(offset)].get(getIndex(offset)); } 这可能适用于单个字节,但如果要处理更大且需要跨越边界的读/写(getLong()或get(byte [])),则需要重写大量代码。 问题是:对于这些场景,你最好的做法是什么,你知道任何可以重复使用的工作解决方案/代码而不重新发明轮子吗?

记忆障碍和TLB

内存障碍保证数据缓存一致。 但是,它是否保证TLB一致? 我发现在线程之间传递MappedByteBuffer时,JVM(java 7 update 1)有时会因内存错误(SIGBUS,SIGSEG)崩溃而出现问题。 例如 final AtomicReference mbbQueue = new AtomicReference(); // in a background thread. MappedByteBuffer map = raf.map(MapMode.READ_WRITE, offset, allocationSize); Thread.yield(); while (!inQueue.compareAndSet(null, map)); // the main thread. (more than 10x faster than using map() in the same thread) MappedByteBuffer mbb = inQueue.getAndSet(null); 没有Thread.yield()我偶尔会在force(),put()和C的memcpy()中崩溃,这些都表示我试图非法访问内存。 使用Thread.yield()我没有遇到任何问题,但这听起来不是一个可靠的解决方案。 有人遇到过这个问题吗? 有关TLB和内存障碍的保证吗? 编辑:操作系统是Centos 5.7,我已经看到了i7和双Xeon机器上的行为。 我为什么这样做? 因为写入消息的平均时间是35-100 […]

用于数据库实现的内存映射MappedByteBuffer或Direct ByteBuffer?

由于所有上下文,这看起来像一个很长的问题。 下面的小说中有两个问题。 感谢您抽出宝贵时间阅读本文并提供帮助。 情况 我正在开发一个可扩展的数据存储区实现,它可以支持在32位或64位系统上处理从几KB到TB或更大的数据文件。 数据存储区采用Copy-on-Write设计; 始终将新数据或修改后的数据附加到数据文件的末尾,并且永远不会对现有数据进行就地编辑。 系统可以托管1个或多个数据库; 每个由磁盘上的文件表示。 实施细节并不重要; 唯一重要的细节是我需要不断地附加到文件并将其从KB增加到MB,再增加到GB到TB,同时随机跳过文件以进行读取操作以回答客户端请求。 首先,思考 乍一看,我知道我想使用内存映射文件,因此我可以将有效管理数据的内存中状态的负担推到主机操作系统和我的代码之外。 然后我的所有代码都需要担心的是在写入时序列化附加到文件的操作,并允许任意数量的同时读者在文件中搜索以回答请求。 设计 因为单个数据文件可以超过MappedByteBuffer的2GB限制,所以我希望我的设计必须包含一个抽象层,它采用写入偏移并将其转换为特定2GB段内的偏移量。 到现在为止还挺好… 问题 这是我开始被挂起的地方,并认为采用不同的设计(下面提出)可能是更好的方法。 通过在SO上阅读20个左右的“内存映射”相关问题,似乎mmap调用对于在分配时想要连续的内存运行是敏感的。 所以,例如,在32位主机操作系统上,如果我试图mmap 2GB文件,由于内存碎片,我的机会很小,映射将成功,而我应该使用像一系列128MB映射的东西来拉动整个档案。 当我想到这个设计时,甚至说使用1024MB mmap大小,对于托管几个庞大数据库的DBMS,所有数据都由1TB文件表示,我现在在内存中有数千个内存映射区域,在我自己的Windows 7测试中尝试为了在多GB文件中创建几百个mmaps,我不仅遇到了exception,每次我尝试分配太多时实际上让JVM陷入段错误,并且在一个案例中我在Windows 7机器中获得了video切断并重新初始化我以前从未见过的操作系统错误弹出窗口。 无论“你永远不会处理那么大的文件”或“这是一个人为的例子”的论点,我可以用这些类型的副作用编写代码的事实使我的内部警报处于高度警戒状态。考虑替代impl(下面)。 BESIDES问题,我对内存映射文件的理解是每次文件生成时我都必须重新创建映射,所以对于这个仅在设计中附加的文件,它实际上在不断增长。 我可以在一定程度上通过以块的forms增加文件(一次说8MB)并且每8MB重新创建映射来解决这个问题,但是不断重新创建这些映射的需要让我感到紧张,尤其是没有明确的unmapfunctionJava支持 。 问题#1 of 2 鉴于我到目前为止的所有发现,我会将内存映射文件视为主要读取大量解决方案或只读解决方案的良好解决方案,但考虑到需要不断重新创建映射,我认为这不是写入量大的解决方案。 然后我看看我周围的景观,像MongoDB这样的解决方案在各处拥抱内存映射文件,我觉得我在这里缺少一些核心组件(我知道它一次分配2GB范围,所以我想他们正在利用这种逻辑来解决重映射成本问题并帮助维持磁盘上的顺序运行。 在这一点上,我不知道问题是Java是否缺少unmap操作,这使得它更加危险并且不适合我的用途,或者如果我的理解不正确并且有人可以指向我North。 替代设计 上面提出的内存映射的另一种设计,如果我对mmap的理解是正确的,我将使用如下: 定义一个合理可配置大小的直接ByteBuffer (粗略地为2,4,8,16,32,64,128KB),使其可以轻松地与任何主机平台兼容(不需要担心DBMS本身导致颠簸情况)和使用原始的FileChannel,一次执行文件1 buffer-capacity-chunk的特定偏移读取 ,完全放弃内存映射文件。 缺点是现在我的代码不得不担心“我从文件中读取的内容是否足以加载完整的记录?” 另一个缺点是我无法利用操作系统的虚拟内存逻辑,让它自动为我保留更多“热”内存数据; 相反,我只是希望操作系统使用的文件缓存逻辑足够大,可以在这里为我做一些有用的事情。 问题#2 of 2 我希望能够确认我对所有这一切的理解。 例如,文件缓存可能很棒,在两种情况下(内存映射或直接读取),主机操作系统将保留尽可能多的热数据,大文件的性能差异可以忽略不计。 或许我对内存映射文件(连续内存)的敏感要求的理解是不正确的,我可以忽略所有这些。