进程空间的VMA结构体中由两个成员,红黑树以及链表,表示其组织方式由两种:
红黑树:
链表类型:
有了上面的图例,下面简单讲一下malloc的分配原理:
首先malloc是通过系统调用brk来完成内存分配的:
SYSCALL_DEFINE1(brk, unsigned long, brk)------------(1)
{
unsigned long retval;
unsigned long newbrk, oldbrk;
struct mm_struct *mm = current->mm;
unsigned long min_brk;
bool populate;
down_write(&mm->mmap_sem);
min_brk = mm->end_data;
if (brk < min_brk)---------------(2)
goto out;
/*
* Check against rlimit here. If this check is done later after the test
* of oldbrk with newbrk then it can escape the test and let the data
* segment grow beyond its set limit the in case where the limit is
* not page aligned -Ram Gupta
*/
if (check_data_rlimit(rlimit(RLIMIT_DATA), brk, mm->start_brk,
mm->end_data, mm->start_data))-------------(3)
goto out;
newbrk = PAGE_ALIGN(brk);--------(4)
oldbrk = PAGE_ALIGN(mm->brk);
if (oldbrk == newbrk)
goto set_brk;
/* Always allow shrinking brk. */
if (brk <= mm->brk) {--------------(5)
if (!do_munmap(mm, newbrk, oldbrk-newbrk))
goto set_brk;
goto out;
}
/* Check against existing mmap mappings. */
if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE))-------------(6)
goto out;
/* Ok, looks good - let it rip. */
if (do_brk(oldbrk, newbrk-oldbrk) != oldbrk)---------------(7)
goto out;
set_brk:
mm->brk = brk;
populate = newbrk > oldbrk && (mm->def_flags & VM_LOCKED) != 0;
up_write(&mm->mmap_sem);
if (populate)
mm_populate(oldbrk, newbrk - oldbrk);---------(8)
return brk;
out:
retval = mm->brk;
up_write(&mm->mmap_sem);
return retval;
}
(1)参数brk表示heap新的边界线
(2)如果新的边界线低于data段,则说明分配出现问题,直接return原来的oldbrk。
(3)RLIMIT相关参数是否满足要求
(4)新旧brk都按照页面对齐,且不足一页部分采用进一法对齐
(5)新边界小于老边界,表示要释放内存,调用do_munmap()函数完成内存释放
(6)查看是否由已经分配好的vma包含当前需要分配的内存边界,如果由则直接return。