一、地址映射
.class文件→ jvm → linux
用【javap -c 字节码名】 可以打印出jvm的指令,最终转成linux系统平台的汇编指令来执行
c/c++,java,python,php,go语言都是指令(text)和数据(data)
- 在程序还没有运行之前,实际上程序的指令和数据的地址都已经分配好了,但是这个指令或者数据的地址是实际的物理地址吗?
答: 不是! 程序的指令和数据所分配的地址不会是物理地址,他们都是虚拟地址(IBM)
程序指令和数据分配的地址 = 虚拟地址 = 虚拟地址空间上的地址
二、映射过程
-
代码运行前,编译生成的指令和数据,地址已经分配好了,(编译的时候,函数和数据的地址是一定要分配的,否则汇编指令没法生成无法形成函数的调用关系和数据的运算关系),但是在程序没运行之前又不知道将来会在哪一块物理内存上运行,所以此时给指令或者数据分配的地址都是虚拟地址——(虚拟地址空间上的地址,linux系统会给每一个进程都分配一个虚拟地址空间,各个进程所能使用的虚拟地址范围都是一样的)
-
当执行当前进程的时候,CPU开始执行当前进程的指令,或者做全局数据的初始化,或者在执行指令过程中,要访问数据都得去内存上取指令或者数据!!!那么不可能直接从发指令和数据的虚拟地址来定位他们在物理内存上的位置,此时要用虚拟地址——物理地址的地址映射
-
由MMU和Linux系统共同完成地址映射,Linux系统负责提供该进程映射所需要的页目录和页表内容,MMU负责具体的映射计算过程,MMU会先把虚拟地址分成10位(pdindex),10位(ptindex),12位(offset)三份。第一个10位表示页目录的下标,第二个10位表示页表的下标,第三个12位表示在物理页面上的偏移量。
-
PD(pdindex) → PT的地址
PT(ptindex) →一个物理页面的起始地址
一个物理页面的起始地址+offset = 指令或者数据最终所在的物理内存的位置。
页目录里存放的是2^ 10 个页表的下标,页表里存放的是2^10 个物理页面的下标,通过发来的指令或者数据一一映射到对应的物理页面,再加上低12位的偏移量表示最终所在的物理内存的位置。linux32位操作系统:2^10 * 2^10 * 2^12 = 1024 1024 4096 = 4G
-
程序启动,任何的物理内存都没有分配,进程只有一个页目录,开始进行地址映射的时候,会不断产生缺页异常,转入缺页异常处理程序,发现导致地址映射失败的原因(是页目录项中没有分配页表,还是页表项中没有分配物理页面…) 然后进行相应的资源分配,重启地址映射过程,最终映射成功。