【linux kernel】虛擬內存分配

一、用戶空間虛擬內存的分配
【接口】
1)mmap()函數
2)malloc()函數


1.mmap()
->sys_mmap() //sys.c
->sys_mmap_pgoff() //見SYSCALL_DEFINE6(mmap_pgoff, unsigned long, addr, unsigned long, len,...) , mm/mmap.c
->vm_mmap_pgoff()
->do_mmap_pgoff()
->get_unmapped_area(struct file *file, unsigned long addr,...)
{
get_area = current->mm->get_unmapped_area; //默認是 arch_get_unmapped_area_topdown()
if (file && file->f_op && file->f_op->get_unmapped_area)
get_area = file->f_op->get_unmapped_area; //如果是文件映射且定義了具體的unmap方法,則使用該方法
addr = get_area(file, addr, len, pgoff, flags);
}

unsigned long arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
 const unsigned long len, const unsigned long pgoff,
 const unsigned long flags)
{
struct vm_area_struct *vma;
struct mm_struct *mm = current->mm;
unsigned long addr = addr0;
struct vm_unmapped_area_info info;


/* requested length too big for entire address space */
if (len > TASK_SIZE - mmap_min_addr) //防止mapsize過大以至於大於3G
return -ENOMEM;


if (flags & MAP_FIXED)
return addr;


/* requesting a specific address */
if (addr) {
addr = PAGE_ALIGN(addr);
vma = find_vma(mm, addr); //find_vma()會查找當前進程mm的VMA信息的RB tree (mm->mm_rb) 
if (TASK_SIZE - len >= addr && addr >= mmap_min_addr &&
(!vma || addr + len <= vma->vm_start)) //如果地址addr沒有被映射,且當前進程的mmap區域(mmap_min_addr~TASK_SIZE)足夠大,那麼直接返回用戶請求的用戶虛擬地址
return addr;
}


info.flags = VM_UNMAPPED_AREA_TOPDOWN;
info.length = len;
info.low_limit = max(PAGE_SIZE, mmap_min_addr);
info.high_limit = mm->mmap_base;
info.align_mask = 0;
addr = vm_unmapped_area(&info);   //查找mm->mm_rb中處於[low_limit~high_limit]範圍的unmaped area


/*
* A failed mmap() very likely causes application failure,
* so fall back to the bottom-up function here. This scenario
* can happen with large stack limits and large mmap()
* allocations.
*/
if (addr & ~PAGE_MASK) {
VM_BUG_ON(addr != -ENOMEM);
info.flags = 0;
info.low_limit = TASK_UNMAPPED_BASE;  //一般是1G處(0x40000000)
info.high_limit = TASK_SIZE; //3G處(0xC0000000)
addr = vm_unmapped_area(&info); //查找mm->mm_rb中處於[low_limit~high_limit]範圍的unmaped area
}


return addr;
}


2. malloc()
->sys_brk() //SYSCALL_DEFINE1(brk, unsigned long, brk), mm/mmap.c
->do_brk() //do_brk(addr, len)函數給從addr到addr+len建立虛擬內存區vm_area_struct(該區的起始地址爲addr,結束地址爲addr+len),該虛擬內存區作爲進程的堆來使用。
->get_unmapped_area(NULL, addr, len, 0, MAP_FIXED)
->mm->brk = brk;

malloc()在Linux上的基本實現是內核的brk系統調用。brk()是一個非常簡單的系統調用,只是簡單地改變mm_struct結構的成員變量brk的值。
內核數據結構mm_struct中的成員變量start_code和end_code是進程代碼段的起始和終止地址,start_data和 end_data是進程數據段的起始和終止地址,
start_stack是進程堆棧段起始地址,start_brk是進程動態內存分配起始地址(堆的起始地址), brk(堆的當前最後地址),就是動態內存分配當前的終止地址。





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章