面试问题汇总:
1.逻辑地址、线性地址,物理地址,虚拟地址分别是什么
物理地址,CPU地址总线传来的地址,物理地址中很大一部分是留给内存条中的内存的
线性地址(Linear Address)也叫虚拟地址(virtual address)是逻辑地址到物理地址变换之间的中间层。在分段部件中逻辑地址是段中的偏移地址,然后加上基地址就是线性地址。
逻辑地址是在有地址变换功能的计算机中,访内指令给出的地址 (操作数) 叫逻辑地址,也叫相对地址,也就是是机器语言指令中,用来指定一个操作数或是一条指令的地址。要经过寻址方式的计算或变换才得到内存储器中的实际有效地址即物理地址。一个逻辑地址由两部份组成,段标识符: 段内偏移量。段标识符是由一个16位长的字段组成,称为段选择符。
2. 段式管理和页式管理的优缺点?
3.Linux中的物理和虚拟存储空间布局
http://blog.csdn.net/tianyahaijiaozd/article/details/6784239
1. Linux中虚拟地址与物理地址之间的转换
80386中逻辑地址到物理地址的转换分为两步:1.段转换(segment convert):逻辑地址转换为线性地址;2.页转换(page convert):线性地址转换为物理地址
段转换:首先根据sector找到descriptor table(GDT)中对应的位置,找到描述符descriptor,每个descriptor项中有base,LIMIT,Type,DPL等,根据base找到该段的起始地址(线性地址中),然后加上offset,得到线性地址
页转换:线性地址的前10位是page dircetory中的索引位置,page directory中存放了page table的物理地址,根据线性地址的第二个10位可以得其在page table中的索引位置,加上page table的物理地址,可以得到该地址的PTE。PTE中记录了该地址对应的物理地址
2.全局描述符表GDT和局部描述符表LDT
1.概况
80386体系结构中地址的转换(逻辑地址--->物理地址)分为两个阶段:
(1) logical address --------> linear address(segment translation)
(2) linear address ---------> physical address (page translation) [optional]
如果没有页转换,那么线性地址就是物理地址(例如boot loader在开启page translation之前,线性地址就是物理地址)
段地址转换的过程中需要使用到全局描述符表GDT(Global Destriptor Table)和局部描述符表LDT(Local Destriptor Table)
A descriptor table is simply a memory array of 8-byte entries that contain descriptors
logical addresss |------selector-----|----------offset----------------|
逻辑地址的selector用于索引描述符表中的entry,每个entry为8B,加上基地址,便可以得到描述符表的位置,并取其中的内容,得到段地址的位置
2.GDT和LDT以及两者的关系
GDT(Global Destriptor Table):每个cpu对应一个GDT,它可以存放在内存中的任何位置,但入口地址(基地址)存放在register(GDTR)中,程序员可以使用LGDT和SGDT进行load 和 store GDT的入口地址
LDT(Local Destriptor Table):每个process一个LDT,入口地址存放在register(LDTR)中,程序员可以只用LLDT和SLDT进行load和store
两者的关系:
可以将GDT理解为一级描述符表,LDT为二级描述符表,(类似一级页表和二级页表),每个进程的LDT也是一段内存,因此它也有一个段描述符,这个描述符就存放在GDT中
每个进程都有自己的程序段,数据段,heap段,stack段,有了LDT,可以将每个进程的code segment, data segment, heap segment, stack segment封装在一起,通过寻找GDT中的不同进行的LDT的位置,然后改变LDTR,便可以实现不同进程见的切换
3.段寄存器(Segment Register)
cs(cose segment), ss, DS(data segment), ES, FS, GS,使用段寄存器的目的是避免进程每次访问地址时都需要进行内存访问
物理地址就是实际的物理内存的地址,逻辑地址是程序指令使用的地址。页表的作用就是实现逻辑地址到物理地址的映射。
x86的32位地址,前20位用于查找页表
3.页表和页表项
TLB作用
由于页表存放在主存中,因此程序每次访存至少需要两次:一次访存获取物理地址,第二次访存才获得数据。想像一下x86_32架构下没有TLB的存在时的情况,对线性地址的访问,首先从PGD中获取PTE(第一次内存访问),在PTE中获取页框地址(第二次内存访问),最后访问物理地址,总共需要3次RAM的访问。
如果有TLB存在,并且TLB hit,那么只需要一次RAM访问即可。当cpu要访问一个虚拟地址/线性地址时,CPU会首先根据虚拟地址的高20位(20是x86特定的,不同架构有不同的值)在TLB中查找。如果是表中没有相应的表项,称为TLB miss,需要通过访问慢速RAM中的页表计算出相应的物理地址。同时,物理地址被存放在一个TLB表项中,以后对同一线性地址的访问,直接从TLB表项中获取物理地址即可,称为TLB hit。
1 所需的也表示否已经缓存在TLB内部(TLB miss或者TLB hit)
2 所需的页表在TLB的哪个条目内
4.地址的保护机制
保护主要包括以下几点:
- 进程不允许修改其只读文本段
- 不允许它读或修改任何内核中的代码和数据结构
- 不允许它它读或者写其他进程的私有存储器
- 不允许修改与其他进程共享的虚拟页面,除非所有的共享者显示地允许它这么做
5.缺页中断过程
发成缺页中断后,执行了那些操作?
当一个进程发生缺页中断的时候,进程会陷入内核态,执行以下操作:
1、检查要访问的虚拟地址是否合法
2、查找/分配一个物理页
3、填充物理页内容(读取磁盘,或者直接置0,或者啥也不干)
4、建立映射关系(虚拟地址到物理地址)
6.Linux中虚拟存储器的实现
task_struct中有一个条目mm_struct,它描述了虚拟存储器的当前状态。pgd和mmap两个变量,pgd指向page directory,mmap指向一个vm_area_structs(区域结构,段)的链表,其中每个vm_area_structs都描述了当前虚拟地址的一个区域。当内核运行该进程时,它就将pgd存放在CR3控制寄存器中
vm_area_structs中:vm_start, vm_end,..
6.动态存储器分配
1.malloc, vmalloc, kmalloc的区别
- kmalloc和vmalloc是分配的是内核的内存,malloc分配的是用户的内存
- kmalloc保证分配的内存在物理上是连续的,vmalloc保证的是在虚拟地址空间上的连续,malloc不保证任何东西(这点是自己猜测的,不一定正确)
- kmalloc能分配的大小有限,vmalloc和malloc能分配的大小相对较大
- 内存只有在要被DMA访问的时候才需要物理上连续
- vmalloc比kmalloc要慢
2.malloc分配器算法
(1)如何实现malloc和free,slab算法,buddy算法
(3) Malloc在什么情况下调用mmap?
从操作系统角度来看,进程分配内存有两种方式,分别由两个系统调用完成:brk和mmap(不考虑共享内存)。brk是将数据段(.data)的最高地址指针_edata往高地址推,mmap是在进程的虚拟地址空间中(一般是堆和栈中间)找一块空闲的。这两种方式分配的都是虚拟内存,没有分配物理内存。在第一次访问已分配的虚拟地址空间的时候,发生缺页中断,操作系统负责分配物理内存,然后建立虚拟内存和物理内存之间的映射关系。
在标准C库中,提供了malloc/free函数分配释放内存,这两个函数底层是由brk,mmap,munmap这些系统调用实现的。