Java 内存映射文件的性能/稳定性-本机或MappedByteBuffer-与普通ol';文件输出流
我支持使用平面文件(纯文本)进行持久化的遗留Java应用程序。由于应用程序的性质,这些文件的大小可以达到每天100s MB,并且应用程序性能的限制因素通常是文件IO。目前,应用程序使用普通的ol'java.io.FileOutputStream将数据写入磁盘 最近,我们有几个开发人员断言,使用内存映射文件(用本机代码(C/C++)实现并通过JNI访问)将提供更高的性能。然而,FileOutputStream已经将本机方法用于其核心方法(即write(byte[]),因此,在没有硬数据或至少是轶事证据的情况下,这似乎是一个很脆弱的假设 关于这一点,我有几个问题:Java 内存映射文件的性能/稳定性-本机或MappedByteBuffer-与普通ol';文件输出流,java,performance,file-io,java-native-interface,production,Java,Performance,File Io,Java Native Interface,Production,我支持使用平面文件(纯文本)进行持久化的遗留Java应用程序。由于应用程序的性质,这些文件的大小可以达到每天100s MB,并且应用程序性能的限制因素通常是文件IO。目前,应用程序使用普通的ol'java.io.FileOutputStream将数据写入磁盘 最近,我们有几个开发人员断言,使用内存映射文件(用本机代码(C/C++)实现并通过JNI访问)将提供更高的性能。然而,FileOutputStream已经将本机方法用于其核心方法(即write(byte[]),因此,在没有硬数据或至少是轶事
[编辑]澄清-应用程序每天都会创建多个大小从100MB到1G的文件。总的来说,应用程序每天可能会写入多个Gig的数据。至于第3点-如果机器崩溃,并且有任何页面没有刷新到磁盘,那么它们就会丢失。另一件事是地址空间的浪费——将文件映射到内存会消耗地址空间(并且需要连续区域),而且,在32位机器上,它有点有限。但您已经说过大约100MB,所以这应该不是问题。还有一件事——扩展mmaped文件的大小需要一些工作
顺便说一句,我还可以给你一些见解。根据我的经验,内存映射文件在实时和持久性用例中都比普通文件访问性能好得多。我在Windows上主要工作于C++,但是Linux的性能是相似的,而且你正计划使用JNI,所以我认为它适用于你的问题。 有关基于内存映射文件构建的持久性引擎的示例,请参阅。我在一个应用程序中使用过它,其中对象是内存映射数据上的简单视图,引擎负责幕后的所有映射工作。这既快速又节省内存(至少与以前版本使用的传统方法相比),而且我们免费获得了提交/回滚事务 在另一个项目中,我必须编写多播网络应用程序。数据以随机顺序发送,以最小化连续数据包丢失的影响(结合FEC和阻塞方案)。此外,数据可能远远超过地址空间(视频文件大于2Gb),因此内存分配是不可能的。在服务器端,文件部分按需进行内存映射,网络层直接从这些视图中提取数据;因此,内存使用率非常低。在接收方,无法预测数据包的接收顺序,因此必须在目标文件上保持有限数量的活动视图,并将数据直接复制到这些视图中。当数据包必须放在未映射区域时,最旧的视图被取消映射(并最终被系统刷新到文件中),并被目标区域上的新视图替换。性能非常出色,特别是因为该系统在将数据提交为后台任务方面做得非常出色,并且很容易满足实时约束 从那时起,我确信即使是最好的精心编制的软件方案也无法通过内存映射文件击败系统的默认I/O策略,因为系统比用户空间应用程序更了解何时以及如何写入数据。另外,重要的是要知道,在处理大数据时,内存映射是必须的,因为数据从未分配(因此消耗内存),而是动态映射到地址空间,并由系统的虚拟内存管理器管理,该管理器总是比堆快。因此,系统总是以最佳方式使用内存,并在需要时在应用程序背后提交数据,而不会影响它
希望有帮助。内存映射I/O不会使磁盘运行更快(!)。对于线性访问,这似乎有点毫无意义 NIO映射的缓冲区才是真正的缓冲区(对于任何合理的实现,通常都要注意)
与其他NIO直接分配的缓冲区一样,这些缓冲区不是普通内存,也不会得到有效的GCD。如果您创建了很多,您可能会发现内存/地址空间不足,而Java堆却没有用完。对于长时间运行的进程来说,这显然是一个问题。通过检查数据在写入过程中的缓冲方式,您可以稍微加快速度。这往往是特定于应用程序的,因为您需要了解预期的数据写入模式。如果数据一致性很重要,那么这里会有权衡 如果您只是从应用程序将新数据写入磁盘,那么内存映射I/O可能不会有多大帮助。我看不出你有什么理由想花时间在一些定制编码的本机解决方案上。对于您的应用程序来说,这似乎太复杂了,fr