最近公司业务上升,该redis哨兵提升为cluster模式,在进行方案设计时,发现对redis的一些基本特性不了解。所以打算了解下redis的基本特性,期间看了一篇文章,和之前了解到的Unix的IO模型以及ByteBuffer.allocateDirector直接申请系统内存有很多共鸣之处,所以打算记录下来。详情点击
Linux系统把内存分为内核空间和用户空间。采用这样的划分,首先较为安全,用户进程不能够随意对内核空间的数据进行操作,在一定程序保证了系统不被破坏,保证系统的稳定性。其次,对于内核空间数据和用户数据分开存放,也是便于管理。二者互不干扰。
对于进程来说,内核进程能够访问内核空间和用户空间。而用户进程只能通过特定的形式来访问内核空间。一般这样做有多点好处。当一个程序进程正在运行时就处于用户态,当发生系统级别的调用时,开始执行内核区的代码,那么该进程就处于内核态。
在Linux内存空间中:主要由两部分构成内存空间,物理内存和SWAP,当物理内存不够使用时,系统会根据一定的策略把暂时不适用的内存放到磁盘中以腾出多余的内存空间,当需要使用这部分数据时,在从SWAP换回到内存中。
内核空间是Linux自身的内存空间,主要提供给程序调度,内存分配,硬件连接等较为底层的程序使用。用户空间时提供给各个进程使用的内存。Linux采用了虚拟内存技术来完成内核空间和用户空间的划分,给每个进程分配一定的虚拟内存空间,只有虚拟内存实际被使用时,才分配物理内存。
那么用户空间主要分为哪些部分:
代码区:存放应用的机器代码,运行过程中不能被修改。具有只读和固定大小的特点。不过我认为运行中的代码不能修改,不再是固定大小,有待商榷。
数据区:存放了应用程序中的全局数据,静态数据和一些常亮字符串,其大小也是固定的。
堆:是运行时程序动态申请的空间,属于程序运行时直接申请,释放的内存资源。
栈:区用来存放函数的传入参数,临时变量,以及返回地址等数据。
未使用区:是分配新内存空间的预备区域。
JVM其实也是一个进程,因此内存空间和普通进程也基本一致,但是JVM将许多本来属于操作系统管理范畴的东西移植到了JVM内部。目的在于减少系统调用的次数。Java NIO。目的在于减少用于读写IO的系统调用的开销。比如C++执行new操作时,会触发一次分配内存空间的系统调用,由操作系统的县城根据对象的大小分配好空间后返回,释放对象时,也需要C++执行delete操作,来触发系统调用,通知操作系统回收对象占用的内存空间。而JVM进程在程序启动时,向操作系统申请一整段的内存区域,然后在Java程序需要内存空间时,按照Java程序的需求分配内存大小。而且Java程序不负责通知JVM何时可以释放对象空间,这个操作由JVM进行。也就是说JVM只会在JVM堆的大小发生变化时,才会进行系统级别的调用。
普通进程内存划分和JVM内存划分的对比
内核空间:由操作系统进程管理和使用,不过一些新的特性使得应用程序可以使用内核内存,或者映射到内核空间,Java NIO就是在这种背景之下产生。对于一般的IO操作来说,数据都需要先发送到内核区,然后再拷贝到用户区,整个是数据IO才算完成。而Java NIO可以直接访问内核内存,提升了Java程序的 IO性能。