精华内容
下载资源
问答
  • 缺页发生在用户态
    2021-07-26 16:56:43

    内核态和用户态之间的区别

     用户态和内核态是操作系统的两种运行级别,两者最大的区别就是特权级别不同。
     用户态拥有最低的特权级,内核态拥有较高的特权级。
     运行再拥护态的程序不能直接访问操作系统内核数据结构和程序。
    

    用户态到内核态的转化原理

    用户态切换到内核态的3种方式

    	系统调用
    
    • 这是用户态主动要求切换到内核态的一种方式,用户进程通过系统调用申请操作系统提供的服务程序完成工作。而系统调用的机制核心还是使用了操作系统为用户特别开放的一个中断来实现,例如Linux的ine 80h中断。

        异常
      
    • 当cpu在执行运行在用户态的程序时,发现了某些事件不可知的异常,这是会触发由当前运行进程切换到处理事件。异常的内核相关程序中,也就到了内核态,比如缺页异常。

    外部设备的中断
    
    • 当外围设备完成用户请求的操作之后,会向cpu发出相应的中断信号,这时cpu会暂停执行下一条将要执行的命令,转而执行中断信号的处理程序,如果先执行的指令是用户态下的程序,那么这个转换的过程自然也就发生了有用户态到内核态的切换,比如硬派的读写操作完成,系统会切换到硬派的中断处理程序中执行后序操作等。

    操作系统为什么要分内核态和用户态

    • 为了安全性。在cpu的一些指令中,有的指令如果用错,将会导致整个系统崩溃。分了内核态和用户态之后,当用户需要操作这些指令时,内核提供了API,可以通过系统调用陷入内核,让内核去执行这些操作。
    更多相关内容
  • 缺页异常理解

    2021-06-30 17:15:57
    由于CPU没有数据就无法进行计算,CPU罢工了用户进程也就出现了缺页中断,进程会从用户态切换到内核态,并将缺页中断交给内核的 Page Fault Handler 处理。 缺页异常并不可怕,只要CPU要的虚拟地址经过MMU的一番寻址...

    术语约定

    VA:Virtual Address 虚拟地址
    PA:Physical Address 物理地址
    MMU:Memory Manage Unit 内存管理单元
    TLB:Translation Lookaside Buffer 旁路快表缓存/地址变换高速缓存
    PTE:Page Table Entry 分页表项
    内存的惰性分配

    以32位的Linux系统为例,每个进程独立拥有4GB的虚拟地址空间,根据局部性原理没有必要也不可能为每个进程分配4GB的物理地址空间。

    64位系统也是一样的道理,只不过空间寻址范围大了很多很多倍,进程的虚拟地址空间会分为几个部分:

    实际上只有程序运行时用到了才去内存中寻找虚拟地址对应的页帧,找不到才可能进行分配,这就是内存的惰性(延时)分配机制。

    对于一个运行中的进程来说,不是所有的虚拟地址在物理内存中都有对应的页,如图展示了部分虚拟地址存在对应物理页的情况:

    虚拟地址空间根据固定大小一般是4KB进行划分,物理内存可以设置不同的页面大小,通常物理页大小和虚拟页大小是一样的,本文按照物理页4KB大小展开。

    经过前面的分析,我们将面临一个问题:如何将虚拟地址准确快速地映射到物理页呢?

    高能预警 敲黑板 本段小结<<<

    1. Linux的虚拟地址空间就是空头支票,看着很大但是实际对应的物理空间只有很少的一部分。

    2.内存的惰性分配是个有效的机制,可以保证内存利用率和服务器利用率,是资源合理配置的方法。

    3.大量的虚拟地址到物理地址的快速准确地查询转换是一个难题。

    CPU如果获取内存中的数据

    CPU并不直接和物理内存打交道,而是把地址转换的活外包给了MMU,MMU是一种硬件电路,其速度很快,主要工作是进行内存管理,地址转换只是它承接的业务之一。

    一起看看MMU是如何搞定地址转换的。

    4.1 MMU和Page Table

    每个进程都会有自己的页表Page Table,页表存储了进程中虚拟地址到物理地址的映射关系,所以就相当于一张地图,MMU收到CPU的虚拟地址之后开始查询页表,确定是否存在映射以及读写权限是否正常,如图:

    对于4GB的虚拟地址且大小为4KB页,一级页表将有2^20个表项,页表占有连续内存并且存储空间大,多级页表可以有效降低页表的存储空间以及内存连续性要求,但是多级页表同时也带来了查询效率问题。

    我们以2级页表为例,MMU要先进行两次页表查询确定物理地址,在确认了权限等问题后,MMU再将这个物理地址发送到总线,内存收到之后开始读取对应地址的数据并返回。

    MMU在2级页表的情况下进行了2次检索和1次读写,那么当页表变为N级时,就变成了N次检索+1次读写。

    可见,页表级数越多查询的步骤越多,对于CPU来说等待时间越长,效率越低,这个问题还需要优化才行。

    本段小结 敲黑板 划重点 <<

    1.页表存在于进程的内存之中,MMU收到虚拟地址之后查询Page Table来获取物理地址。

    2.单级页表对连续内存要求高,于是引入了多级页表,但是多级页表也是一把双刃剑,在减少连续存储要求且减少存储空间的同时降低了查询效率。

    4.2 MMU和TLB的故事

    MMU和TLB的故事就这样开始了…

    CPU觉得MMU干活虽然卖力气,但是效率有点低,不太想继续外包给它了,这一下子把MMU急坏了。

    MMU于是找来了一些精通统计的朋友,经过一番研究之后发现CPU用的数据经常是一小搓,但是每次MMU都还要重复之前的步骤来检索,害,就知道埋头干活了,也得讲究方式方法呀!

    找到瓶颈之后,MMU引入了新武器,江湖人称快表的TLB,别看TLB容量小,但是正式上岗之后干活还真是不含糊。

    当CPU给MMU传新虚拟地址之后,MMU先去问TLB那边有没有,如果有就直接拿到物理地址发到总线给内存,齐活。

    TLB容量比较小,难免发生Cache Miss,这时候MMU还有保底的老武器页表 Page Table,在页表中找到之后MMU除了把地址发到总线传给内存,还把这条映射关系给到TLB,让它记录一下刷新缓存。

    TLB容量不满的时候就直接把新记录存储了,当满了的时候就开启了淘汰大法把旧记录清除掉,来保存新记录,彷佛完美解决了问题。

    在TLB和Page Table加持之下,CPU感觉最近MMU比较给力了,就问MMU怎么做到的?MMU就一五一十告诉了CPU。

    CPU说是个不错的路子,随后说出了自己的建议:TLB还是有点小,缓存不命中也是经常发生的,要不要搞个大的,这样存储更多访问更快?

    MMU一脸苦笑说道大哥TLB很贵的,要不你给涨点外包费?话音未落,CPU就说涨工资是不可能了,这辈子都不可能了。

    高能预警 敲黑板 本段小结<<<

    1. CPU要根据用户进程提供的虚拟地址来获取真实数据,但是它并不自己做而是交给了MMU。

    2. MMU也是个聪明的家伙,集成了TLB来存储CPU最近常用的页表项来加速寻址,TLB找不到再去全量页表寻址,可以认为TLB是MMU的缓存。

    3. TLB的容量毕竟有限,为此必须依靠Page Table一起完成TLB Miss情况的查询,并且更新到TLB建立新映射关系。

    缺页异常Page Fault大揭秘

    设想CPU给MMU的虚拟地址在TLB和Page Table都没有找到对应的物理页帧或者权限不对,该怎么办呢?

    没错,这就是缺页异常Page Fault,它是一个由硬件中断触发的可以由软件逻辑纠正的错误。

    5.1 PageFault,它来了

    假如目标内存页在物理内存中没有对应的页帧或者存在但无对应权限,CPU 就无法获取数据,这种情况下CPU就会报告一个缺页错误。

    由于CPU没有数据就无法进行计算,CPU罢工了用户进程也就出现了缺页中断,进程会从用户态切换到内核态,并将缺页中断交给内核的 Page Fault Handler 处理。

    缺页异常并不可怕,只要CPU要的虚拟地址经过MMU的一番寻址之后没有找到或者找到后无权限,就会出现缺页异常,因此触发异常后的处理流程将是重点内容。

    5.2 缺页错误的分类处理

    缺页中断会交给PageFaultHandler处理,其根据缺页中断的不同类型会进行不同的处理:

    Hard Page Fault 也被称为Major Page Fault,翻译为硬缺页错误/主要缺页错误,这时物理内存中没有对应的页帧,需要CPU打开磁盘设备读取到物理内存中,再让MMU建立VA和PA的映射。
    Soft Page Fault 也被称为Minor Page Fault,翻译为软缺页错误/次要缺页错误,这时物理内存中是存在对应页帧的,只不过可能是其他进程调入的,发出缺页异常的进程不知道而已,此时MMU只需要建立映射即可,无需从磁盘读取写入内存,一般出现在多进程共享内存区域。
    Invalid Page Fault 翻译为无效缺页错误,比如进程访问的内存地址越界访问,又比如对空指针解引用内核就会报segment fault错误中断进程直接挂掉。

    5.3 缺页错误出现的原因

    不同类型的Page Fault出现的原因也不一样,常见的几种原因包括:

    非法操作访问越界 这种情况产生的影响也是最大的,也是Coredump的重要来源,比如空指针解引用或者权限问题等都会出现缺页错误。
    使用malloc新申请内存 malloc机制是延时分配内存,当使用malloc申请内存时并未真实分配物理内存,等到真正开始使用malloc申请的物理内存时发现没有才会启动申请,期间就会出现Page Fault。
    访问数据被swap换出 物理内存是有限资源,当运行很多进程时并不是每个进程都活跃,对此OS会启动内存页面置换将长时间未使用的物理内存页帧放到swap分区来腾空资源给其他进程,当存在于swap分区的页面被访问时就会触发Page Fault从而再置换回物理内存。

    敲黑板 划重点 本段小结:<<<

    触发Page Fault的原因可能有很多,归根到底也只有几种大类:

    1. 如使用共享内存区域,没有存储VA->PA的映射但是存在物理页帧的软缺页错误,在Page Table/TLB中建立映射关系即可。

    2. 访问的地址在物理内存中确实不存在,需要从磁盘/swap分区读入才能使用,这种性能影响会比较大,因为磁盘太慢了,尽量使用高性能的SSD来降低延时。

    3. 访问的地址内存非法,缺页错误会升级触发SIGSEGV信号结束进程,这种属于可以导致进程挂掉的一种缺页错误。

    全文总结

    本文粗浅地和大家一起学习了Page Fault的相关知识点,包括Linux虚拟地址和物理地址的关系、CPU获取内存数据的过程、MMU和TLB&页表的协同配合、缺页异常产生的原因和分类处理。

    展开全文
  • linux内存管理--缺页异常处理

    千次阅读 2013-11-19 15:51:18
    缺页异常linux内核处理中占有非常重要的位置,很多linux特性,如写时复制,页框延迟分配,内存回收中的磁盘和内存交换,都需要借助缺页异常来进行,本文介绍了linux缺页处理的情形和代码分析。
    1 缺页异常在linux内核处理中占有非常重要的位置,很多linux特性,如写时复制,页框延迟分配,内存回收中的磁盘和内存交换,都需要借助缺页异常来进行,缺页异常处理程序主要处理以下四种情形:
    1请求调页: 当进程调用malloc()之类的函数调用时,并未实际上分配物理内存,而是仅仅分配了一段线性地址空间,在实际访问该页框时才实际去分配物理页框,这样可以节省物理内存的开销,还有一种情况是在内存回收时,该物理页面的内容被写到了磁盘上,被系统回收了,这时候需要再分配页框,并且读取其保存的内容。
    2写时复制:当fork()一个进程时,子进程并未完整的复制父进程的地址空间,而是共享相关的资源,父进程的页表被设为只读的,当子进程进行写操作时,会触发缺页异常,从而为子进程分配页框。
    3地址范围外的错误:内核访问无效地址,用户态进程访问无效地址等。
    4内核访问非连续性地址:用于内核的高端内存映射,高端内存映射仅仅修改了主内核页表的内容,当进程访问内核态时需要将该部分的页表内容复制到自己的进程页表里面。


    2 缺页异常处理程序有可能发生在用户态或者内核态的代码中,在这两种形态下,有可能访问的是内核空间或者用户态空间的内存地址,因此,按照排列组合,需要考虑下列的四种情形,如图所示:

    1缺页异常发生在内核态


    2缺页异常发生在用户态


    3源代码分析(选自2.6.10内核)

    3.1 do_page_fault()
    fastcall void do_page_fault(struct pt_regs *regs, unsigned long error_code)
    {
    	struct task_struct *tsk;
    	struct mm_struct *mm;
    	struct vm_area_struct * vma;
    	unsigned long address;
    	unsigned long page;
    	int write;
    	siginfo_t info;
    	//将引发缺页异常的线性地址保存在address变量里面
    	__asm__("movl %%cr2,%0":"=r" (address));
    
    	if (notify_die(DIE_PAGE_FAULT, "page fault", regs, error_code, 14,
    					SIGSEGV) == NOTIFY_STOP)
    		return;
    	
    	tsk = current;
    	//info是内核发送信号使用的信息结构体
    	info.si_code = SEGV_MAPERR;
    
    	//该分支表明发生缺页时是发生在访问内核空间时
    	if (unlikely(address >= TASK_SIZE)) { 
    		//该分支表示发生缺页异常时,代码是在内核态访问内核态不存在
    		//的地址,转到vmalloc_fault处理分支,可能是访问了不连续的内核页面
    		if (!(error_code & 5))
    			goto vmalloc_fault;
    		//做相应出错处理
    		goto bad_area_nosemaphore;
    	} 
    
    	mm = tsk->mm;
    	//在中断或者软中断中访问用户态空间,发生问题,是不可以的,因为中断或者
    	//软中断不代表任何的进程,mm为NULL代表着该进程是内核线程,内核线程
    	//继承了上一个普通进程页表,不能对其进行修改
    	if (in_atomic() || !mm)
    		goto bad_area_nosemaphore;
    
    	//尝试获取到读锁,若获得读锁失败时
    	if (!down_read_trylock(&mm->mmap_sem)) {
    		//在内核态访问用户态的地址,这种情况发生在在
    		//进程的系统调用中去访问用户态的地址,在访问
    		//地址前,内核是不会去写对应的读锁的,所以可能是
    		//别的进程写了,相应的锁,所以需要等待,其它情况
    		//属于错误情况
    		if ((error_code & 4) == 0 &&
    		    !search_exception_tables(regs->eip))
    			goto bad_area_nosemaphore;
    		down_read(&mm->mmap_sem);
    	}
    
    	//下面这几句话是来判断出错地址是否在进程的线性区内
    	vma = find_vma(mm, address);
    	//不在线性区内,地址错误
    	if (!vma)
    		goto bad_area;
    	//在线性区内,跳到正常处理部分
    	if (vma->vm_start <= address)
    		goto good_area;
    	//下面这些代码属于扩展进程栈的相关处理,该地址可能由push或者pusha指令引起
    	//向低地址扩展的栈其线性区的标志位会置上VM_GROWSDOWN
    	if (!(vma->vm_flags & VM_GROWSDOWN))
    		goto bad_area;
    	if (error_code & 4) {//异常发生在用户态
    		//对于栈操作,发生错误的内存地址不应该比esp小太多,不该小32
    		//个字节以上
    		if (address + 32 < regs->esp)
    			goto bad_area;
    	}
    	//扩展进程的用户态堆栈
    	if (expand_stack(vma, address))
    		goto bad_area;
    good_area:
    	info.si_code = SEGV_ACCERR;
    	write = 0;
    	switch (error_code & 3) {
    		default://写,存在该页框,写时复制的情况
    		case 2:	//写但不存在该页框
    			//该线性区不让写,发生错误
    			if (!(vma->vm_flags & VM_WRITE))
    				goto bad_area;
    			write++;
    			break;
    		case 1:	//读,存在该页框
    			goto bad_area;
    		case 0:	//读但是不存在该页框,缺页,需要进行调页
    			if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
    				goto bad_area;
    	}
    
     survive:
    	//在handle_mm_fault()函数里面处理缺页的情况
    	switch (handle_mm_fault(mm, vma, address, write)) {
    		case VM_FAULT_MINOR:
    			//在没有阻塞的情况下,完成了调页
    			tsk->min_flt++;
    			break;
    		case VM_FAULT_MAJOR:
    			//在阻塞的情况下,完成了调页操作
    			tsk->maj_flt++;
    			break;
    		case VM_FAULT_SIGBUS:
    			//发生其他错误
    			goto do_sigbus;
    		case VM_FAULT_OOM:
    			//内存不足
    			goto out_of_memory;
    		default:
    			BUG();
    	}
    
    	/*
    	 * Did it hit the DOS screen memory VA from vm86 mode?
    	 */
    	if (regs->eflags & VM_MASK) {
    		unsigned long bit = (address - 0xA0000) >> PAGE_SHIFT;
    		if (bit < 32)
    			tsk->thread.screen_bitmap |= 1 << bit;
    	}
    	up_read(&mm->mmap_sem);
    	return;
    
    /*
     * Something tried to access memory that isn't in our memory map..
     * Fix it, but check if it's kernel or user first..
     */
    bad_area:
    	up_read(&mm->mmap_sem);
    
    bad_area_nosemaphore:
    	//该错误发生在用户态代码访问时
    	if (error_code & 4) {
    		
    		if (is_prefetch(regs, address, error_code))
    			return;
    
    		tsk->thread.cr2 = address;
    		tsk->thread.error_code = error_code | (address >= TASK_SIZE);
    		tsk->thread.trap_no = 14;
    		info.si_signo = SIGSEGV;
    		info.si_errno = 0;
    		info.si_addr = (void __user *)address;
    		//发送sigsegv信号给当前的进程
    		force_sig_info(SIGSEGV, &info, tsk);
    		return;
    	}
    
    //剩下的错误,发生在内核态
    no_context:
    	//是否有动态修正代码,该异常通常发生在将用户态线性地址
    	//作为参数传递给了系统调用,该错误发生在内核态访问一个
    	//用户态地址,但用户态地址不属于进程的地址空间
    	if (fixup_exception(regs))
    		return;	
     	if (is_prefetch(regs, address, error_code))
     		return;
    
    	bust_spinlocks(1);
    	//发生了真正的内核错误,往输出上打印相关错误信息
    	if (address < PAGE_SIZE)
    		printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
    	else
    		printk(KERN_ALERT "Unable to handle kernel paging request");
    	printk(" at virtual address %08lx\n",address);
    	printk(KERN_ALERT " printing eip:\n");
    	printk("%08lx\n", regs->eip);
    	asm("movl %%cr3,%0":"=r" (page));
    	page = ((unsigned long *) __va(page))[address >> 22];
    	printk(KERN_ALERT "*pde = %08lx\n", page);
    	
    #ifndef CONFIG_HIGHPTE
    	if (page & 1) {
    		page &= PAGE_MASK;
    		address &= 0x003ff000;
    		page = ((unsigned long *) __va(page))[address >> PAGE_SHIFT];
    		printk(KERN_ALERT "*pte = %08lx\n", page);
    	}
    #endif	
    	//产生Oops的消息
    	die("Oops", regs, error_code);
    	bust_spinlocks(0);
    	//退出相关进程
    	do_exit(SIGKILL);
    
    out_of_memory:
    	//内存不足,删除当前进程
    	up_read(&mm->mmap_sem);
    	if (tsk->pid == 1) {
    		yield();
    		down_read(&mm->mmap_sem);
    		goto survive;
    	}
    	printk("VM: killing process %s\n", tsk->comm);
    	if (error_code & 4)//用户态进程,杀死用户态进程
    		do_exit(SIGKILL);
    	goto no_context;
    
    do_sigbus:
    	//发送SIGBUS信号给当前进程
    	up_read(&mm->mmap_sem);
    
    	//内核态进程,生成oops等
    	if (!(error_code & 4))
    		goto no_context;
    
    	if (is_prefetch(regs, address, error_code))
    		return;
    	//用户态进程的话,发送SIGBUS给当前用户态进程
    	tsk->thread.cr2 = address;
    	tsk->thread.error_code = error_code;
    	tsk->thread.trap_no = 14;
    	info.si_signo = SIGBUS;
    	info.si_errno = 0;
    	info.si_code = BUS_ADRERR;
    	info.si_addr = (void __user *)address;
    	force_sig_info(SIGBUS, &info, tsk);
    	return;
    
    vmalloc_fault:
    	{
    		//在内核态访问内核空间内存,访问非连续性内存
    		int index = pgd_index(address);
    		unsigned long pgd_paddr;
    		pgd_t *pgd, *pgd_k;
    		pmd_t *pmd, *pmd_k;
    		pte_t *pte_k;
    
    		asm("movl %%cr3,%0":"=r" (pgd_paddr));
    		pgd = index + (pgd_t *)__va(pgd_paddr);
    		pgd_k = init_mm.pgd + index;
    
    		if (!pgd_present(*pgd_k))
    			goto no_context;
    
    		pmd = pmd_offset(pgd, address);
    		pmd_k = pmd_offset(pgd_k, address);
    		if (!pmd_present(*pmd_k))
    			goto no_context;
    		//主要操作就是把主内核页表上对应的表项复制到当前进程的页表中
    		set_pmd(pmd, *pmd_k);
    		
    		pte_k = pte_offset_kernel(pmd_k, address);
    		if (!pte_present(*pte_k))
    			goto no_context;
    		return;
    	}
    }
    3.2 handle_mm_fault()
    int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct * vma,
    	unsigned long address, int write_access)
    {
    	pgd_t *pgd;
    	pmd_t *pmd;
    
    	__set_current_state(TASK_RUNNING);
    	pgd = pgd_offset(mm, address);
    
    	inc_page_state(pgfault);
    
    	if (is_vm_hugetlb_page(vma))
    		return VM_FAULT_SIGBUS;	
    	
    	spin_lock(&mm->page_table_lock);
    	//找到相应的pmd表的地址,没有的话,分配一个
    	pmd = pmd_alloc(mm, pgd, address);
    	
    	if (pmd) {
    		//找到对应的pte表的地址,即页表的地址,找不到
    		//的话,分配一个
    		pte_t * pte = pte_alloc_map(mm, pmd, address);
    		//进行相应的缺页处理:
    		//1请求调页,2写时复制
    		if (pte)
    			return handle_pte_fault(mm, vma, address, write_access, pte, pmd);
    	}
    	spin_unlock(&mm->page_table_lock);
    	return VM_FAULT_OOM;
    }
    3.3 handle_pte_fault()
    static inline int handle_pte_fault(struct mm_struct *mm,
    	struct vm_area_struct * vma, unsigned long address,
    	int write_access, pte_t *pte, pmd_t *pmd)
    {
    	pte_t entry;
    
    	entry = *pte;
    	if (!pte_present(entry)) {
    		//页面从未被访问过,需要申请页面进行调页,匿名映射
    		//或者是磁盘文件映射都有可能
    		if (pte_none(entry))
    			return do_no_page(mm, vma, address, write_access, pte, pmd);
    		//非线性磁盘文件映射
    		if (pte_file(entry))
    			return do_file_page(mm, vma, address, write_access, pte, pmd);
    		//相关页框被作为交换页写到了磁盘上
    		return do_swap_page(mm, vma, address, pte, pmd, entry, write_access);
    	}
    	//写时复制
    	if (write_access) {
    		if (!pte_write(entry))
    			return do_wp_page(mm, vma, address, pte, pmd, entry);
    
    		entry = pte_mkdirty(entry);
    	}
    	entry = pte_mkyoung(entry);
    	ptep_set_access_flags(vma, address, pte, entry, write_access);
    	update_mmu_cache(vma, address, entry);
    	pte_unmap(pte);
    	spin_unlock(&mm->page_table_lock);
    	return VM_FAULT_MINOR;
    }
    


    展开全文
  • 【Linux_选择题】(D27 0526)

    千次阅读 2021-06-15 22:20:13
    请求 read 系统调用会导致 CPU 从用户态切换到核心态 Ⅲ. read 系统调用的参数应包含文件的名称 ( A )   A 仅Ⅰ、 Ⅱ   B 仅Ⅰ、 Ⅲ   C 仅Ⅱ、 Ⅲ   D Ⅰ、 Ⅱ和Ⅲ 2、下列关于虚拟存储的叙述中,正确的...

    【Linux_选择题】(D27 0526)

    1、若一个用户进程通过read 系统调用读取一个磁盘文件中的数据,则下列关于此过程的叙述中,正确的是( )。 Ⅰ. 若该文件的数据不在内存中,则该进程进入睡眠等待状态 Ⅱ. 请求 read 系统调用会导致 CPU 从用户态切换到核心态 Ⅲ. read 系统调用的参数应包含文件的名称 ( A )

      A 仅Ⅰ、 Ⅱ
      B 仅Ⅰ、 Ⅲ
      C 仅Ⅱ、 Ⅲ
      D Ⅰ、 Ⅱ和Ⅲ


    2、下列关于虚拟存储的叙述中,正确的是(B)

      A 虚拟存储只能基于连续分配技术
      B 虚拟存储只能基于非连续分配技术
      C 虚拟存储容量只受外存容量的限制
      D 虚拟存储容量只受内存容量的限制


    3、下列选项中,不可能在用户态发生的事件是(C)

      A 系统调用
      B 外部中断
      C 进程切换
      D 缺页

      分析:

      1、系统调用可能在用户态和内核态发生,系统调用把应用程序的请求(用户态的请求)传入内核,由内核(内核态)处理请求并将结果返回给应用程序(用户态) 用户态->核心态
      2、中断的发生与CPU当前的状态无关,既可以发生在用户态,又可以发生在内核态,因为无论系统处于何种状态都需要处理外部设备发来的中断请求。
      3、进程切换在核心态下完成,不能发生在用户态。原因:需要调度处理器和系统资源,为保证系统安全?
      4、缺页(异常)也是用户态->内核态


    4、在虚拟内存管理中,地址变换机构将逻辑地址变为物理地址,形成该逻辑地址的阶段是(C)

      A 编辑
      B 编译
      C 链接
      D 装载

      分析:

      编译后的程序需要经过链接才能装载,而链接后形成的目标程序中的地址也就是逻辑地址。以 C 语言为例:C 程序经过 预处理 → 编译 → 汇编 → 链接 产生了可执行文件,其中链接的前一步是产生可重定位的二进制目标文件。C 语言采用源文件独立编译的方法,如程序main.c,file1.c,file2.c,file1.h,file2.h 在链接的前一步生成了 main.o,file1.o,file2.o,这些目标模块的逻辑地址都从0开始,但只是相对于该模块的逻辑地址。链接器将这三个文件、libc 和其库文件链接成一个可执行文件。链接阶段主要完成重定位,形成整个程序的完整逻辑地址空间 。
      例如,file1.o 的逻辑地址为 0 ~ 1023,main.o 的逻辑地址为 0 ~ 1023 ,假设链接时将 file1.o 链接在 main.o 之后,则链接之后 file1.o 对应的逻辑地址应为 1024 ~ 2047,整个过程如图所示。

    在这里插入图片描述


    5、在缺页处理过程中,操作系统执行的操作可能是(D)

      Ⅰ.修改页表 Ⅱ.磁盘 I/O Ⅲ.分配页框

       A 仅Ⅰ、 Ⅱ
      B 仅Ⅱ
      C 仅Ⅲ
      D Ⅰ、 Ⅱ和Ⅲ


    6、下面选项中,满足短任务优先且不会发生饥饿现象的调度算法是(B)

      A 先来先服务
      B 高响应比优先
      C 时间片轮转
      D 非抢占式短任务优先


    7、下列选项中,降低进程优先级的合理时机是(A)

      A 进程的时间片用完
      B 进程刚完成I/O,进入就绪列队
      C 进程持久处于就绪列队
      D 进程从就绪状态转为运行态


    8、在使用锁保证线程安全时,可能会出现活跃度失败的情况,活跃度失败主要包括 (D)

      A 死锁
      B 饥饿
      C 活锁
      D 以上全部


    9、下列选项中,导致创建新进程的操作是 ( C )

      I 用户登陆成功 II 设备分配 III 启动程序执行

      A 仅I和II
      B 仅II和III
      C 仅I和III
      D I、II和III


    10、对进程和线程的描述,以下正确的是 ( D )

      A 父进程里的所有线程共享相同的地址空间,父进程的所有子进程共享相同的地址空间
      B 改变进程里面主线程的状态会影响到其他线程的行为,改变父进程的状态不会影响到其他子进程
      C 多线程会引起死锁,而多进程不会
      D 以上选项都不正确

      分析:

      父进程和子进程 都有自己独立的地址空间;

      父进程结束,所有子进程都结束,进程结束,所有线程都结束;

      如果多个进程同时占有对方需要的资源而同时请求对方的资源,而它们在得到请求之前不会释放所占有的资源,那么就会导致死锁的发生,也就是进程不能实现同步;

      多线程和多进程都会引起死锁,一般说的死锁指的是进程间的死锁。


    展开全文
  • 进程调度属于系统调用核心态执行,命令解释程序属于命令接口,它在用户态执行。 25.支持多线程的系统中,进程 P 创建的若干个线程不能共享的是 A.进程 P 的代码段 C.进程 P 的全局变量 B.进程 P 中打开的文件 D....
  • 一、进程内核栈、用户栈 1.进程的堆栈 ?...当进程在用户空间运行时,cpu堆栈指针寄存器里面的内容是用户堆栈地址,使用用户栈;当进程内核空间时,cpu堆栈指针寄存器里面的内 容是内核栈空间地
  • 缺页异常(WHO I AM?)

    2020-09-22 17:43:56
    此时,由于CPU没有数据就无法进行计算,CPU罢工了用户进程也就出现了缺页中断,进程会从用户态切换到内核态,操作系统将进程放入阻塞队列中,并将缺页中断交给内核的 Page Fault Handler 处理,待处理过后将进程...
  • 操作系统它基于CPU之上,只用到了CPU的两种状态,一个内核态,一个用户态,内核态运行CPU的第 0 等级,用户态运行CPU的第 3 等级。 2.操作系统的用户态和内核态之间的切换 首先内核态与用户态是操作系统的两...
  • 用户空间的缺页异常可以分为两种情况--1、触发异常的线性地址处于用户空间的vma中,但还未分配物理页,如果访问权限OK的话内核就给进程分配相应的物理页了2、触发异常的线性地址不处于用户空间的vma中,这种情况得...
  • CPU用户态和内核态

    2022-02-24 20:55:19
    这里写目录标题内核态与用户态...用户态的程序运行3级特权级上,因为这是最低特权级,是普通的用户进程运行的特权级,大部分用户直接面对的程序都是运行在用户态。内核态的程序运行0级特权级上。 处于用户态执行时
  • 用户态和内核态的区别

    千次阅读 2021-02-16 20:14:22
    用户态(User Mode):运行用户程序 二、指令划分 特权指令:只能由操作系统使用、用户程序不能使用的指令。 举例:启动I/O 内存清零 修改程序状态字 设置时钟 允许/禁止终端 停机 非特权指令:用户程序可以使用...
  • 有些场景下可以减少用户态进程内存访问时缺页中断的次数,从而降低进程内核态cpu使用率。如下列频繁分配释放内存导致的性能问题的分析场景: **场景:**一个压力测试,每秒执行2000次下列请求:每次请求都malloc一...
  • 凡是涉及到IO读写、内存分配等硬件资源的操作时,往往不能直接操作,而是通过一种叫系统调用的过程,让程序陷入到内核态运行,然后内核态的CPU执行有关硬件资源操作指令,得到相关的硬件资源后返回到用户态继续...
  • 近日,我写内核模块的时候犯了一个低级错误:直接access用户态的内存而没有使用copy_to_user/copy_from_user!内核看来,用户态提供的虚拟地址是不可信的,所以...
  • CPU的用户态和内核态

    2022-03-26 14:48:35
    用户态的使用命令是非特权指令,例如控制转移 算数运算 取数指令 访管指令(使用户程序从用户态陷入内核态) 特权级别: R3相当于用户态; 执行状态 : 进程能够访问的内存空间和对象被限制,而且占有的处理器可以被...
  • 线程用户态和内核态

    千次阅读 2019-05-14 13:59:52
    (1)用户态和内核态的概念? —>内核态: CPU可以访问内存所有数据, 包括外围设备, 例如硬盘, 网卡. CPU也可以将自己从一个程序切换到另一个程序 —>用户态: 只能受限的访问内存, 且不允许访问外围设备. 占用CPU...
  • 1. 内核态和用户态、内核线程和用户线程等解释操作系统调度CPU的最小单元是线程,也叫轻量级进程(Light Weight Process),一个进程里可以创建多个线程,这些线程都拥有各自的计数器、堆栈和局部变量等属性,并且...
  • 1、用户态和内核态的区别? 明白这两个概念之前,我们得...用户空间下执行,我们把此时运行得程序的这种状态成为用户态,而当这段程序执行内核的空间执行时,这种状态称为内核态。 当一个任务(进程)执行系统...
  • 面试官接着问:如果时钟中断处理程序发生缺页中断,怎么办? 小明嘟囔:咋手表坏了还会缺液,这啥手表。。。液压手表?要加几号油... 面试官:小明同学,滚。。。 ” 上面是一个段子,但是这是一个面试必考...
  • 进程用户态和内核态及其切换过程

    千次阅读 2020-05-24 22:50:10
    1.进程的堆栈     内核创建进程的时候,会为进程创建相应的堆栈。每个进程会有两个栈,一个用户栈,...当进程因为中断或者系统调用而陷入内核之行时,进程所使用的堆栈也要从用户栈转到内核栈
  • 内核态和用户态

    2020-11-23 08:49:05
    CPU的两种工作状态:内核态(管态)和用户态(目态) 内核态: 1.系统中既有操作系统的程序,也有普通用户程序。为了安全性和稳定性,操作系统的程序不能随便访问,这就是内核态。即需要执行操作系统程序就必须转换...
  • 用户态:供应用程序运行的空间,只能受限制地访问内存 内核态:控制计算机的硬件资源,例如协调CPU资源,分配内存资源,并且提供稳定的环境 为什么要划分 1. 安全性 给不同的操作给与不同的“权限”。有些指令是...
  • 用户态和核心态的区别

    千次阅读 2020-05-14 17:17:06
    用户态(User Mode):运行用户程序 2.指令划分: 特权指令:只能由操作系统使用、用户程序不能使用的指令。 举例:启动I/O 内存清零 修改程序状态字 设置时钟 允许/禁止终端 停机 非特权指令:用户程序可以...
  • 内核态和用户态的区别当一个任务(进程)执行系统调用而陷入内核代码中执行时,我们就称进程处于内核状态。此时处理器处于特权级最高的(0级)内核代码。...当进程执行用户自己的代码时,则称其处于用户态。即此时处...
  • 用户态与内核态

    2021-07-30 21:00:57
    一、什么是用户态、内核态 一般的操作系统对执行权限进行分级,分别为用用户态和内核态。...用户态则权利有限,例如内存分配中,有一部分内存是仅为内核态使用的,用户态code则不允许访问那些内存地址...
  • Linux的内核态与用户态

    千次阅读 2021-12-12 22:36:02
    引言:最近看Java内置锁的实现时看到重量级锁的性能开销较大,主要因为使用重量级锁需要用到一个pthread_mutex_lock系统调用,导致Java程序需要在用户态和内核态之间切换,由于不太了解用户态和内核态到底是什么,...
  • 当CPU执行运行在用户态的程序时,发现了某些事件不可知的异常,这是会触发由当前运行进程切换到处理此。异常的内核相关程序中,也就到了内核态,比如缺页异常。 3、外围设备的中断 当外围设备完成用户请求的操作...
  • 一、内核态与用户态的定义计算机系统中,通常运行着两类程序:系统程序和应用程序,为了保证系统程序不被应用程序有意或无意地破坏,为计算机设置了两种状态:1、 系统态(也称为管态或核心态),操作系统系统态...
  • 用户态和内核态

    2022-03-15 10:31:11
    运行在用户态的程序不能直接访问操作系统内核数据结构和程序 操作系统的数据都是存放于系统空间的,用户进程的数据是存放于用户空间的。 * 分开来存放,就让系统的数据和用户的数据互不干扰,保证系统的稳定性。 * ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 9,533
精华内容 3,813
关键字:

缺页发生在用户态