本文作者Alex已经从事Java开发15年了,最近帮助开发了COBOL和Magik语言的JVM 。当前,他正致力于Micro Focus的Java性能测试工具。在本文中,他阐述了在标准硬件中实现高速、多线程虚拟内存的可能性及方案。原文内容如下。
你想在标准硬件上运行TB级甚至PB级内存的JVM吗?你想与内存交互一样读写文件,且无需关心文件的打开、关闭、读、写吗?
JVM的64位地址空间使这些成为可能。
首先,不要在观念上将内存和磁盘进行区分,而是统一处理为内存映射文件。在32位地址空间时,内存映射文件只是为了高速访问磁盘;因为受限于虚拟机的有限地址空间,并不支持大规模的虚拟内存或大文件。如今JVM已经发展为64位,而且可以在64位操作系统上运行。在一个进程的地址空间中,内存映射文件大小就可以达到TB甚至PB。
进程无需关心内存是在RAM或是磁盘上。操作系统会负责处理,而且处理得非常高效。
我们可以使用Java的MappedByteBuffer类访问内存映射文件。该类的实例对象与普通的ByteBuffer一样,但包含的内存是虚拟的——可能是在磁盘上,也可能是在RAM中。但无论哪种方式,都是由操作系统负责处理。因为的ByteBuffer的大小上限是Intger.MAX_VALUE,我们需要若干个ByteBuffer来映射大量内存。在这个示例中,我映射了40GB。
这是因为我的Mac只有16GB内存,下面代码证明了这一点!
public MapperCore(String prefix, long size) throws IOException { coreFile = new File(prefix + getUniqueId() + ".mem"); // This is a for testing - to avoid the disk filling up coreFile.deleteOnExit(); // Now create the actual file coreFileAccessor = new RandomAccessFile(coreFile, "rw"); FileChannel channelMapper = coreFileAccessor.getChannel(); long nChunks = size / TWOGIG; if (nChunks > Integer.MAX_VALUE) throw new ArithmeticException("Requested File Size Too Large"); length = size; long countDown = size; long from = 0; while (countDown > 0) { long len = Math.min(TWOGIG, countDown); ByteBuffer chunk = channelMapper.map(MapMode.READ_WRITE, from, len); chunks.add(chunk); from += len; countDown -= len; } } |
上面的代码在虚拟内存创建了40GB MappedByteBuffer对象列表。读取和写入时只需要注意处理两个内存模块的跨越访问。完整代码的可以在这里找到。