Java内存映射原理与实现

01. 虚拟内存与内存映射文件

1.1. 概念

  • 虚拟内存
    虚拟内存属于硬盘的一部分,是计算机RAM与硬盘的数据交换分区

    由于实际的物理内存远小于进程的地址空间,这就需要把内存中暂时不用到的数据放到硬盘上一个特殊的地方,当请求的数据不在内存中时,系统产生却页中断,内存管理器便将对应的内存页重新从硬盘调入物理内存。

  • 内存映射文件
    内存映射文件是由一个文件到一块内存的映射。

    应用程序可以通过内存指针对磁盘上的文件进行访问,就如同访问加载了文件的内存,因此内存文件映射非常适合于用来管理大文件。

1.2 区别

  • 磁盘文件
    虚拟内存使用的硬盘只能是页面文件
    内存映射使用的磁盘可以是任何磁盘文件。
  • 架构
  1. 虚拟内存是架构在物理内存之上。

    引入原因:实际的物理内存运行程序所需的空间。即使现在计算机中的物理内存越来越大,程序的尺寸也在增长,将所有运行着的程序全部加载到内存中不经济也非常不现实。

  2. 内存映射文件架构在程序的地址空间之上

    32位机地址空间只有4G,而某些大文件的尺寸可要要远超出这个值,因此,用地址空间中的某段应用文件中的一部分可解决处理大文件的问题,在32中,使用内存映射文件可以处理2的64次(64EB)大小的文件.原因内存映射文件,除了处理大文件,还可用作进程间通信。

02. 内存映射文件的原理

“映射”就是建立一种对应关系,主要是指硬盘上文件的位置与进程逻辑地址空间中一块相同区域之间一一对应。这种关系纯属是逻辑上的概念,物理上是不存在的,原因是进程的逻辑地址空间本身就是不存在的,在内存映射过程中,并没有实际的数据拷贝,文件没有被载入内存,只是逻辑上放入了内存,具体到代码,就是建立并初始化了相关的数据结构,这个过程有系统调用mmap()实现,所以映射的效率很高。
在这里插入图片描述
上面说到建立内存映射没有进行实际的数据拷贝,那么进程又怎么能最终通过内存操作访问到硬盘上的文件呢?

  1. 调用mmap(),相当于要给内存映射文件分配了虚拟内存,它会返回一个指针ptr,这个ptr所指向的是一个逻辑地址,要操作其中的数据,必须通过MMU(Memory Management Unit,即内存管理单元)将逻辑地址转换成物理地址,如图1中过程2所示。
  2. 建立内存映射并没有实际拷贝数据,这时MMU在地址映射表中是无法找到与ptr相对应的物理地址的,也就是MMU失败,将产生一个缺页中断,缺页中断的中断响应函数会在swap(也就是交换分区)中寻找相对应的页面,如果找不到(也就是该文件从来没有被读入内存的情况),则会通过mmap()建立的映射关系,从硬盘上将文件读取到物理内存中,如图1中过程3所示。
  3. 如果在拷贝数据时,发现物理内存不够用,则会通过虚拟内存机制(swap)将暂时不用的物理页面交换到硬盘上,如图1中过程4所示。

03. 内存映射文件的效率

了解过内存映射文件都知道,它比传统的IO读写数据快很多,那么,它为什么会这么快,从代码层面上来看,从硬盘上将文件读入内存,都是要经过数据拷贝,并且数据拷贝操作是由文件系统和硬件驱动实现的,理论上来说,拷贝数据的效率是一 样的。其实,原因是read()是系统调用,其中进行了数据拷贝,它首先将文件内容从硬盘拷贝到内核空间的一个缓冲区,如图2中过程1,然后再将这些数据拷贝到用户空间,如图2中过程2,在这个过程中,实际上完成 了两次数据拷贝 ;而mmap()也是系统调用,如前所述,mmap()中没有进行数据拷贝,真正的数据拷贝是在缺页中断处理时进行的,由于mmap()将文件直接映射到用户空间,所以中断处理函数根据这个映射关系,直接将文件从硬盘拷贝到用户空间,只进行了 一次数据拷贝 。因此,内存映射的效率要比read/write效率高。
在这里插入图片描述

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java 8中的ConcurrentHashMap是线程安全的哈希表实现,它支持并发读写操作而不需要全局锁定。它的实现原理主要有以下几个方面: 1. 分段锁策略:ConcurrentHashMap将整个数据结构分成若干个Segment(段),每个Segment维护着一个独立的散列桶数组。每个Segment内部都有一个可重入锁,不同的线程可以同时访问不同的Segment,从而实现并发读写的能力。 2. 散列桶数组:ConcurrentHashMap使用散列桶数组来存储键值对。每个散列桶上都有一个链表,用于解决哈希冲突。当多个键映射到同一个散列桶时,它们会被链接到同一个链表上。 3. CAS操作:ConcurrentHashMap使用CAS(Compare and Swap)操作来保证并发更新操作的原子性。CAS是一种无锁算法,它通过比较内存中的值与期望值是否相等来确定是否更新。如果相等,则执行更新操作;否则,重新尝试。 4. 扩容机制:ConcurrentHashMap在插入新元素时,如果当前Segment的负载因子(即链表长度)超过阈值,则会触发扩容操作。扩容时,会创建一个新的散列桶数组,并将原来的键值对重新分配到新的散列桶中。这个过程可以通过加锁来保证线程安全。 总的来说,ConcurrentHashMap通过分段锁策略、散列桶数组、CAS操作和扩容机制来实现线程安全的并发读写操作。它在多线程环境下能够提供较好的性能和可伸缩性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值