操作系统

当前位置:金沙棋牌 > 操作系统 > JVM学习准备知识,linux地址类型

JVM学习准备知识,linux地址类型

来源:http://www.logblo.com 作者:金沙棋牌 时间:2019-11-29 12:41

Linux中使用的地址类型列表:

要学习Java虚拟机,我觉得先要建立完整的知识体系,了解一些操作系统内存管理方面的知识:

  • 虚拟地址空间(virtual address space)
  • 物理地址(physical address)
  • 逻辑地址(logical address)
  • 线性地址(linear address)
  • 金沙棋牌,虚拟地址(virtual address)
  • 用户空间&内核空间
  • 内存映射文件
    这里将逐一对这些概念展开描述。

用户虚拟地址(User virtual addresses)

虚拟地址空间(virtual address space)

虚拟地址 vs 物理地址

金沙棋牌 1

现代CPU都支持多任务处理,每个进程运行在自己的沙箱环境中,这个沙箱就是虚拟地址空间(Virtual Address Space)。CPU读/写内存,都会使用虚拟地址。在32位的操作系统上,一个指针的大小是4字节,寻址能力是0x00000000 ~ 0xFFFFFFFF(0~2^32 - 1),最大值即表示4GB大小的容量。在64位的操作系统上,虚拟地址的理论大小为2^64=16EB(1EB=1024 * 1024 * 1024GB),但实际上不会使用全64bit,以降低地址转换的成本,具体使用多少bit因CPU架构而异,x86架构通常是采用低48bit的VAS(256TB)。

使用虚拟地址的优势:

  • 各进程的虚拟地址彼此隔离,不会相互影响。
  • 程序可以使用一系列相邻的虚拟地址来访问物理内存中不相邻的大内存缓冲区。
  • 程序可以使用一系列虚拟地址来访问大于可用物理内存的内存缓冲区。当物理内存的供应量变小时,内存管理器会将物理内存页保存到磁盘文件。数据或代码页会根据需要在物理内存与磁盘之间移动。

用户空间程序可见的普通地址。用户虚拟地址的长度为32位或64位,依赖于底层的硬件体系架构,每个进程有它自己的虚拟地址空间。

各种地址(physical address|linear adress...)

这里引用知乎上的一个回答Linux 线性地址,逻辑地址和虚拟地址的关系?,感觉讲的比较清楚:

在 Intel 平台下,逻辑地址(logical address)是 selector:offset 这种形式,selector 是 CS (code segment,代码段)寄存器的值,offset 是 EIP (instruction pointer,指令指针)寄存器的值。如果用 selector 去 GDT( global (segment) descriptor table,全局段号记录表) 里拿到 segment base address(段基址) 然后加上offset(段内偏移),这就得到了 linear address。我们把这个过程称作段式内存管理。
如果再把 linear address 切成四段,用前三段分别作为索引去PGD、PMD、Page Table里查表,最终就会得到一个页表项(Page Table Entry),那里面的值就是一页物理内存的起始地址,把它加上 linear address 切分之后第四段的内容(又叫页内偏移)就得到了最终的 physical address。我们把这个过程称作页式内存管理。
问题来了,为什么没提到 virtual address,这是个什么东西?其实在 Intel IA-32 手册里并没有提到这个术语,但是在内核的确是用到了这个概念,比如__va和__pa这两个宏定义。看似神秘的 virtual address 究其本质就是程序里面使用的地址比如一个指针值,指针的本质就是 EIP 寄存器里的值,说直白点,virtual address 就是 EIP 寄存器的值。你会发现我们上面说过,logical address 由 selector 和 offset 两部分组成,offset 也是 EIP 寄存器的值,所以结论为:logical address 的 offset 正是 virtual address,它俩是一个东西。
既然搞明白了 logical address 和 virtual address 的关系,那么我们再来看下,linear address 和 virtual address 是什么关系。在上面讲到的段式内存管理中,Linux 内核会将 segment base address(段基址)设成 0,于是就有 linear address = 0+offset,又因为 virtual address 就是 offset,所以算出的 linear address在数值上等于 virtual address,注意,是数值上等于,它们之间是差了段基址的,只不过段基址为 0 罢了。
网上很多资料认为逻辑地址是虚拟地址的别名,其实它们不是一个东西。还有很多资料把线性地址当作虚拟地址的别名,其实它们也不是一个东西,只是Linux在x86下将它们搞得数值相等而已,虽然值相等但是本质不同。

简单总结一下 intel x86_32架构内存寻址过程:

  • Linux简化了分段机制(将段基址设成0),使得虚拟地址和线性地址总是一致。
  • 逻辑地址--分段--线性地址(虚拟地址) --分页--物理地址

物理地址(Physical addresses)

用户空间&内核空间

x86_32架构下,每个进程分配4G的虚拟地址空间,用户空间从0到3G(0xC0000000),内核空间占据3G到4G,每个进程可以通过系统调用进入内核,因此Linux内核空间由系统内的所有进程共享,而每个进程的用户空间是完全独立的。
内核空间是由内核负责映射,它并不会跟着进程变化,是固定的,而用户空间对应进程,随着进程的切换而变化。
用户模式(user mode)下运行的代码可以访问用户空间,但不能访问内核空间。此限制可防止用户模式代码读或更改受保护的操作系统数据结构。内核模式(kernel mode)下运行的代码既可以访问用户空间,也可以访问内核空间。
intel cpu提供RING0 ~ RING3四种级别的运行模式(简称R0 ~ R3),R0级别最高,R3级别最低。Linux使用R3级别运行用户模式,R0运行内核模式。R3状态不能访问R0的地址空间,包括代码和数据。因此用户模式只能通过系统调用切换到内核模式,在完成操作后再切换回用户模式

处理器和系统内存之间使用的地址。物理地址的长度为32位或64位;32位操作系统上有时也可以使用大于32位的物理地址(PAE)

内存映射文件

I/O操作是调用操作系统提供的read()、write()系统调用函数完成对应操作的,调用时进程由用户态切换到内核态,将读到的数据缓存在内核空间的缓冲区中,再拷贝到用户空间中,由于内核会预读更多的数据到缓冲区,因此下一次读操作可能是直接从内核缓冲区拷贝到用户空间,节省了一次低效的磁盘I/O操作。
内存映射文件则不需要将数据先读到内核缓冲区,而是将用户空间中的一段地址空间区域与文件对象建立映射关系(由系统调用mmap()完成)。在进程第一次引用这段地址时,会触发缺页中断,并由中断处理函数根据映射关系直接将文件数据拷贝到用户空间。与普通I/O相比,少了把文件数据读到内核缓冲区这一步,因此内存映射文件的效率更高。

在JVM中有direct memory(直接内存)这块区域,是调用native函数直接分配的堆外内存,然后在Java堆中通过一个DirectByteBuffer对象作为这块内存的引用,这样避免了Java堆和native堆之间来回拷贝数据。

总线地址(Bus addresses)

外部总线和系统内存之间使用的地址。通常总线地址和物理地址是等同的,但也不一定。有些体系结构上,有一个IOMMU(IO memory management unit)将总线地址重映射为物理地址。IOMMU在许多场景下有帮助,比如将分散的物理内存重映射成连续的总线地址,设备看起来总线地址是连续的。但这也带来了额外的工作量,比如在DMA操作时,需要对IOMMU额外的编程(填写映射项)。当然,总线地址是和体系结构高度相关的。

内核逻辑地址(Kernel logical addresses)

内核逻辑地址组成了内核的普通地址空间。这些地址映射部分或全部主存地址,而且经常被认为它们貌似就是物理地址。在大多数体系架构上,逻辑地址和相关的物理地址之间就只差了一个固定的偏移量。逻辑地址的类型为硬件本地指针大小,因此,在32位重载的系统上,可能不能访问所有的物理地址。逻辑地址的类型通常为unsigned long或者void *。通过kmalloc分配出来的内存,地址类型为逻辑地址。

内核虚拟地址(Kernel virtual addresses)

内核虚拟地址和内核逻辑地址相似,因为它们就是内核空间地址向物理内存的映射。与内核逻辑地址不同的是,内核虚拟地址在映射时,不必线性或者一对一映射成物理地址。所有的内核逻辑地址为内核虚拟地址,但许多内核虚拟地址却不是内核逻辑地址。比如vmalloc分配出来的内存为内核虚拟地址(但未直接映射为物理地址)。kmap函数返回的也是内核虚拟地址。内核虚拟地址通常储存在指针变量中。

 

宏__pa()(定义在<asm/page.h>)将内核逻辑地址转换成物理地址。宏__va()将物理地址转换回内核逻辑地址,但只针对低地址生效。

本文由金沙棋牌发布于操作系统,转载请注明出处:JVM学习准备知识,linux地址类型

关键词: