首页 > *nix技术, 内存管理, 内核技术, 应用程序 > 应用程序与物理内存之间的关系

应用程序与物理内存之间的关系

2012年4月3日 发表评论 阅读评论 8,024 次浏览

应用程序与物理内存本没有直接关系,因为应用程序看到的都是虚拟内存,至于这块虚拟内存到底映射哪块物理内存,应用程序并不关心,也没有能力关心。不过既然文章标题叫做“应用程序与物理内存之间的关系”就说明应用程序与物理内存之间虽然没有直接关系,但有间接关系;我们知道应用程序能够在运行时主动申请、释放的内存主要有Heap(malloc/free/…)、Mapping(mmap/munmap/…),这里就以Heap为例(因为前面曾详细分析过应用程序里的堆内存管理),看它们之间有如何微妙的间接关系。
当应用程序malloc一块内存时,如果应用程序自己管理的堆内存还有缓冲(这个不难理解,对于应用程序的内存申请,内核都比较大方,即使应用程序只申请4字节的内存,内核也会给它4KB,假设内存页大小为4KB),那么就直接使用了,无需再向内核讨要;否则的话,只有调用sbrk()或mmap()向内核讨要新的内存了,dlmalloc解析连载完整word文档里已经描述过,应用程序优先调用sbrk()以扩展当前Heap的连续空间,如果无法扩展(比如此时,前面待延伸的内存地址空间恰好被某个文件映射占用了),那就只有mmap()申请另外的一段地址空间。
以sbrk()为例,syscall到内核里对应的是do_brk()函数,带有两个参数,第一个为内存地址addr,第二个为增减的长度len,可正(比如:malloc)可负(比如:free),这个函数所做的工作只有一个,那就是根据进程请求情况进行判断并调整进程的vma(或增大或减小或拆分或合并等)并返回给进程对应的地址空间,当然这是成功的情况,如果vma判断调整失败,那就直接返回ENOMEM或其它错误码。
既然应用程序进行内存申请时没和物理内存扯上关系,那么当应用程序实际进行内存访问时,总该和物理内存扯上关系了吧?的确也是如此。当应用程序访问(读写)一个并没有对应物理地址的逻辑地址时,CPU就会产生一个中断号为14的中断,该中断将被内核捕获。查看源码的话,在这里

/* Set of traps needed for early debugging. */
void __init early_trap_init(void)
{
	set_intr_gate_ist(1, &debug, DEBUG_STACK);
	/* int3 can be called from all */
	set_system_intr_gate_ist(3, &int3, DEBUG_STACK);
	set_intr_gate(14, &page_fault);
	load_idt(&idt_descr);
}

page_fault()函数间接调用do_page_fault()

/*
 * This routine handles page faults.  It determines the address,
 * and the problem, and then passes it off to one of the appropriate
 * routines.
 */
dotraplinkage void __kprobes
do_page_fault(struct pt_regs *regs, unsigned long error_code)
{
...
	/* Get the faulting address: */
	/* 获得引发中断的地址 */
	address = read_cr2();
...
	/* 查找该地址对应的vma */
	vma = find_vma(mm, address);
	if (unlikely(!vma)) {
		bad_area(regs, error_code, address);
		return;
	}
	/* 一般情况,合法 */
	if (likely(vma->vm_start <= address))
		goto good_area;
	/* 特殊情况,比如栈 */
	if (unlikely(!(vma->vm_flags & VM_GROWSDOWN))) {
		bad_area(regs, error_code, address);
		return;
	}
...
	/*
	 * Ok, we have a good vm_area for this memory access, so
	 * we can handle it..
	 */
good_area:
...
	/*
	 * If for any reason at all we couldn't handle the fault,
	 * make sure we exit gracefully rather than endlessly redo
	 * the fault:
	 */
	/* 分配页表、物理内存页 */ 
	fault = handle_mm_fault(mm, vma, address, flags);
...
	up_read(&mm->mmap_sem);
}

这个函数比较复杂,不过这里只描述与本文相关的内容,首先是read_cr2()调用获得引发中断的地址,这个读取cr2寄存器即可(cr2用于发生页异常时报告出错信息,当发生页异常时,处理器会自动把引起页异常的线性地址保存在cr2中);接着调用find_vma()函数查找该地址对应的vma,如果该地址合法,那么肯定能够找到对应的vma(因为之前已经通过sbrk()或mmap()把它加入到vma了),如果没找到,那么执行错误流程并函数返回。接着在做有效性判断,如果一切OK的话,最后开始调用handle_mm_fault()函数分配页表以及真实的物理内存页:handle_mm_fault() -> handle_pte_fault() -> do_anonymous_page() ->slab/slub -> physical memory。

转载请保留地址:http://www.lenky.info/archives/2012/04/1449http://lenky.info/?p=1449


备注:如无特殊说明,文章内容均出自Lenky个人的真实理解而并非存心妄自揣测来故意愚人耳目。由于个人水平有限,虽力求内容正确无误,但仍然难免出错,请勿见怪,如果可以则请留言告之,并欢迎来讨论。另外值得说明的是,Lenky的部分文章以及部分内容参考借鉴了网络上各位网友的热心分享,特别是一些带有完全参考的文章,其后附带的链接内容也许更直接、更丰富,而我只是做了一下归纳&转述,在此也一并表示感谢。关于本站的所有技术文章,欢迎转载,但请遵从CC创作共享协议,而一些私人性质较强的心情随笔,建议不要转载。

法律:根据最新颁布的《信息网络传播权保护条例》,如果您认为本文章的任何内容侵犯了您的权利,请以Email或书面等方式告知,本站将及时删除相关内容或链接。

  1. 本文目前尚无任何评论.
  1. 本文目前尚无任何 trackbacks 和 pingbacks.