学习RocketMQ时,遇到Java的ByteBufer实现原理涉及的知识
Bytebuffer分为两种:间接地和直接的,所谓直接就是指MappedByteBuffer,直接使用内存映射(java的话就意味着在JVM之外分配虚拟地址空间);而间接的ByteBuffer是在JVM的堆上面的,说白了就是管理一群byte数组的包装。
目录结构:
一、补充物理内存、虚拟内存、页面文件、交换区知识
二、ByteBuffer使用和实现以及文件内存映射
三、Java NIO之内存映射文件——MappedByteBuffer
四、内存映射文件原理
一、补充物理内存、虚拟内存、页面文件、交换区知识:
文章来自:https://www.cnblogs.com/oneway1990/p/7794749.html
物理内存,顾名思义,就是实实在在存在的那个东西,插在你电脑主板上的内存条所提供的空间。
页面文件,这个是硬盘上的一块空间,在Windows下表现为一个文件。这个页面文件存在的意义就是在物理内存被占用满以后,将物理内存中的东西移动到硬盘上的这个空间,腾出物理内存给需要的应用程序来使用。
交换区,这个是物理内存和页面文件空间的总和,“交换”的含义,则是指在硬盘文件、CPU和其它IO之间进行数据的传递和暂存(这句话对于了解计算机运行基本流程的人来说应该可以理解)。
虚拟内存,这个概念恐怕是目前为止最为含混不清的一个东西了,会有很多种不同的含义。在这里,我先说一下在一个程序猿眼中的虚拟内存是个啥。
很显然,这个世界上的电脑配置是五花八门,可用的物理内存数量也是分为很多等级的。作为一个苦逼的程序猿,我们不可能在考虑程序逻辑的时候还要去 考虑客户的机器有多少内存可以用,也不可能去详细调查实际的物理内存地址是多少到多少,好在OS会为我们完成这些工作。每一个运行的进程,都会获得一个 4G的内存地址空间,这就是所谓的虚拟内存,这里面的所有地址都是虚拟的,和物理内存啥的并不直接挂钩。而在操作系统那头,这些虚拟地址所映射到的实际地 址,可以是物理内存地址,也可以是页面文件的地址。如果是物理内存小于这个虚拟地址的范围的话,映射的物理内存还可能是重复的物理内存地址片段,使用的时 候可以通过清空内存数据,将内存数据写入页面文件这样的方式进行物理内存的重新利用,以提高物理内存的利用效率。
而不少人,尤其是对Windows刚有所了解的人,所理解的虚拟内存,往往是指页面文件。这也是微软的意见,他们在自己的操作系统中就是这么写的,见下图:
而在Aida64,或者说是曾经的Everest中,虚拟内存是交换区 + 物理内存 = 物理内存 * 2 + 页面文件。老实说,我并没有理解这个的概念是什么。
其实上述虚拟内存的说法都没有什么问题,都是约定俗成的说法,关键是要搞清楚什么时候的“虚拟内存”是指什么,概念不混淆就可以。
顺便吐个槽,我发现Win7的内存调度很诡异,物理内存不是边占用边释放的,总是等到占用率很高(接近满)的时候,来个集中释放,也就是写入页面 文件。我的笔记本硬盘性能不咋样,给这么一搞整个就会卡死半天,而下载软件开时间长一点的话很容易就把物理内存占满。据说是这 Superfetch(拼错没?)的效果,关了以后内存占用率确实上升的慢了一点,不过占用率感觉还是偏高,看着真不爽。
几个概念
1、交换空间swap
交换空间是专门用于临时存储内存的一块磁盘空间,通常在页面调度和交换进程数据时使用,通常推荐交换空间的大小应该是物理内存的二到四倍。
2、页面调度
页面调度是指从磁盘向内存传输数据,以及相反的过程,这个过程之所以被称为页面调度,是因为Unix内存被平均划分成大小相等的页面;
通常页面大小为4KB和8KB(在Solaris中可以用pagesize命令查看)。
当可执行程序开始运行时,它的映象会一页一页地从磁盘中换入,与此类似,当某些内存在一段时间内空闲,就可以把它们换出到交换空间中,这样就可以把空闲的RAM交给其他需要它的程序使用。
3、交换
页面调度通常容易和交换的概念混淆,页面调度是指把一个进程所占内存的空闲部分传输到磁盘上,而交换是指当系统中实际的内存已不够满足新的分配需求时,把整个进程传输到磁盘上,交换活动通常意味着内存不足。
UNIX内存管理:UNIX系统通过2种方法进行内存管理,“调页算法”,“交换技术”。
调页算法是将内存中最近不常使用的页面换到磁盘上,把常使用的页面(活动页面)保留在内存中供进程使用。
交换技术是系统将整个进程,而不是部分页面,全部换到磁盘上。正常情况下,系统会发生一些交换过程。
当内存严重不足时,系统会频繁使用调页和交换,这增加了磁盘I/O的负载。进一步降低了系统对作业的执行速度,即系统I/O资源问题又会影响到内存资源的分配。
二、ByteBuffer使用和实现以及文件内存映射
转至:https://blog.csdn.net/hjding/article/details/54986154
ByteBuffer和CharBuffer等其它Buffer的直接子类一样,顾名思义,就是存取字节的Buffer。很多数据最终在和底层交互上都是使用了字节,而更大的数据是由字节组合而成。谈到字节的组合,就不得不谈到字节大小的定义和字节的顺序。关于字节是8位构成的这个结论,似乎现在的计算机教材都理所当然地描述出来,我们也默认接受了这样的一个事实。但实际上字节由8个二进制位构成也是有渊源和优点的,这与IBM的360主机有关,详细的可以参考这个。下面说说组成数据的字节顺序。
对于多字节的数据在系统中的存储,通常按数据的高位和低位在系统内存中的高地址和低地址存放分为大端(big endian)和小端(little endian)两种方式。
在Java API中,有ByteOrder这样一个pu