JAVA NIO之浅谈内存映射文件原理与DirectMemory

   JAVA类库中的NIO包相对于IO 包来说有一个新功能是内存映射文件,日常编程中并不是经常用到,但是在处理大文件时是比较理想的提高效率的手段。本文我主要想结合操作系统中(OS)相关方面的知识介绍一下原理。

   在传统的文件IO操作中,我们都是调用操作系统提供的底层标准IO系统调用函数  read()、write() ,此时调用此函数的进程(在JAVA中即java进程)由当前的用户态切换到内核态,然后OS的内核代码负责将相应的文件数据读取到内核的IO缓冲区,然后再把数据从内核IO缓冲区拷贝到进程的私有地址空间中去,这样便完成了一次IO操作。至于为什么要多此一举搞一个内核IO缓冲区把原本只需一次拷贝数据的事情搞成需要2次数据拷贝呢? 我想学过操作系统或者计算机系统结构的人都知道,这么做是为了减少磁盘的IO操作,为了提高性能而考虑的,因为我们的程序访问一般都带有局部性,也就是所谓的局部性原理,在这里主要是指的空间局部性,即我们访问了文件的某一段数据,那么接下去很可能还会访问接下去的一段数据,由于磁盘IO操作的速度比直接访问内存慢了好几个数量级,所以OS根据局部性原理会在一次 read()系统调用过程中预读更多的文件数据缓存在内核IO缓冲区中,当继续访问的文件数据在缓冲区中时便直接拷贝数据到进程私有空间,避免了再次的低效率磁盘IO操作。在JAVA中当我们采用IO包下的文件操作流,如:  

   FileInputStream in = new FileInputStream("D:\\java.txt");
   in.read();

   JAVA虚拟机内部便会调用OS底层的 read()系统调用完成操作,如上所述,在第二次调用 in.read()的时候可能就是从内核缓冲区直接返回数据了(可能还有经过 native堆做一次中转,因为这些函数都被声明为 native,即本地平台相关,所以可能在C代码中有做一次中转,如 win32中是通过 C代码从OS读取数据,然后再传给JVM内存)。既然如此,JAVA的IO包中为啥还要提供一个 BufferedInputStream 类来作为缓冲区呢。关键在于四个字,"系统调用"!当读取OS内核缓冲区数据的时候,便发起了一次系统调用操作(通过native的C函数调用),而系统调用的代价相对来说是比较高的,涉及到进程用户态和内核态的上下文切换等一系列操作,所以我们经常采用如下的包装:

   FileInputStream in = new FileInputStream("D:\\java.txt"); 
   BufferedInputStream buf_in = new BufferedInputStream(in);
   buf_in.read();

  这样一来,我们每一次 buf_in.read() 时候,BufferedInputStream 会根据情况自动为我们预读更多的字节数据到它自己维护的一个内部字节数组缓冲区中,这样我们便可以减少系统调用次数,从而达到其缓冲区的目的。所以要明确的一点是 BufferedInputStream 的作用不是减少 磁盘IO操作次数(这个OS已经帮我们做了),而是通过减少系统调用次数来提高性能的。同理 BufferedOuputStream , BufferedReader/Writer 也是一样的。在 C语言的函数库中也有类似的实现,如 fread(),这个函数就是 C语言中的缓冲IO,作用与BufferedInputStream()相同.

    这里简单的引用下JDK6 中 BufferedInputStream 的源码验证下:

 

public
class BufferedInputStream extends FilterInputStream {

    private static int defaultBufferSize = 8192;

    /**
     * The internal buffer array where the data is stored. When necessary,
     * it may be replaced by another array of
     * a different size.
     */
    protected volatile byte buf[];
  /**
     * The index one greater than the index of the last valid byte in 
     * the buffer. 
     * This value is always
     * in the range <code>0</code> through <code>buf.length</code>;
     * elements <code>buf[0]</code>  through <code>buf[count-1]
     * </code>contain buffered inpu
  • 25
    点赞
  • 60
    收藏
    觉得还不错? 一键收藏
  • 25
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值