内存之malloc

1. mmap/malloc之后,首次使用会有较高的latency

使用过mmap映射文件的同学会发现一个问题,search程序访问对应的内存映射时,处理query的时间会有latecny会陡升,究其原因是因为mmap只是建立了一个逻辑地址,linux的内存分配测试都是采用延迟分配的形式,也就是只有你真正去访问时采用分配物理内存页,并与逻辑地址建立映射,这也就是我们常说的缺页中断。 

缺页中断分为两类,一种是内存缺页中断,这种的代表是malloc,利用malloc分配的内存只有在程序访问到得时候,内存才会分配;另外就是硬盘缺页中断,这种中断的代表就是mmap,利用mmap映射后的只是逻辑地址,当我们的程序访问时,内核会将硬盘中的文件内容读进物理内存页中,这里我们就会明白为什么mmap之后,访问内存中的数据延时会陡增。

出现问题解决问题,上述情况出现的原因本质上是mmap映射文件之后,实际并没有加载到内存中,要解决这个文件,需要我们进行索引的预加载,这里就会引出本文讲到的另一函数madvise,这个函数会传入一个地址指针,已经一个区间长度,madvise会向内核提供一个针对于于地址区间的I/O的建议,内核可能会采纳这个建议,会做一些预读的操作。例如MADV_SEQUENTIAL这个就表明顺序预读。

如果感觉这样还不给力,可以采用read操作,从mmap文件的首地址开始到最终位置,顺序的读取一遍,这样可以完全保证mmap后的数据全部load到内存中。

2.

brk - 小块内存

mmap - 大块内存(128k)

do_brk()

SYSCALL_DEFINE1(brk, unsigned long, brk)

{

origbrk = mm->brk;//记录原始的brk位置

//这里应该是处理使用brk释放的时候,如果brk位置小于了min值,就什么也不做

if (brk < min_brk)

            goto out;


    //做rlimit限制检查     

    if (check_data_rlimit(rlimit(RLIMIT_DATA), brk, mm->start_brk,

            mm->end_data, mm->start_data))

            goto out;

//记录新brk的值和旧值,做页边界对齐

    newbrk = PAGE_ALIGN(brk);

    oldbrk = PAGE_ALIGN(mm->brk);

    //在页边界对齐之后,如果相同,就没有什么要做的(因为当前已经是这样了)

    if (oldbrk == newbrk) {

            mm->brk = brk;

            goto success;

    }

    //申请brk位置小于当前mm的brk位置,这是要做缩减操作

    if (brk <= mm->brk) {

        int ret;

//使用新的brk位置更新mm的记录值

        mm->brk = brk;

        //将缩减的部分(由newbrk开始,长度为oldbrk-newbrk的空间释放unmap掉)

        ret = __do_munmap(mm, newbrk, oldbrk-newbrk, &uf, true);

        if (ret < 0) {

        //如果没能正确umap,要把mm的记录值恢复,这次缩减失败

                mm->brk = origbrk;

                goto out;

        } else if (ret == 1) {

                downgraded = true;

        }

        goto success;

    }


        //这里是继续做brk扩充的步骤

        next = find_vma(mm, oldbrk);

        if (next && newbrk + PAGE_SIZE > vm_start_gap(next))

                goto out;

        //真正做brk扩充,把新的空间建立vma加入mm

        //如果能做vm_merge(将旧的vma扩展包括了新的地址范围),vma是(起始地址,长度)的对表示

        //如果不能merge, 就新键vma,将新vma加入mm的vma-link

        if (do_brk_flags(oldbrk, newbrk-oldbrk, 0, &uf) < 0)

                goto out;

        //更新mm的记录值

        mm->brk = brk;

success:

//如果是brk扩展 而且使用 mlockall(flags)设置了VM_LOCKED

        populate = newbrk > oldbrk && (mm->def_flags & VM_LOCKED) != 0;

        if (downgraded)

        //如果是在做缩减操作,释放mm的read lock

                mmap_read_unlock(mm);

        else

            //如果是在做扩展或者缩减失败,释放mm的write lock

                mmap_write_unlock(mm);

        userfaultfd_unmap_complete(mm, &uf);

        if (populate)

        //如果设定了VM_LOCKED的扩张,就做内存填充,提前处理缺页,分配物理内存

                mm_populate(oldbrk, newbrk - oldbrk);

        return brk;


out:   

        retval = origbrk;

        mmap_write_unlock(mm);

        return retval;

}

SYSCALL_DEFINE1(mlockall, int, flags)

\__ apply_mlockall_flags(flags)

SYSCALL_DEFINE0(munlockall)

\__ apply_mlockall_flags(0)

  \__ apply_mlockall_flags()

    \__ current->mm->def_flags |= VM_LOCKED

//如果没定义了MMU,mm_populate()是空函数

//如果设定了VM_LOCKED,为新的空间填充物理页面

mm_populate(unsigned long addr, unsigned long len) 

\__ __mm_populate(addr, len, 1)

  \__ __mm_populate(unsigned long start, unsigned long len, int ignore_errors)

    \__ populate_vma_page_range(vma, nstart, nend, &locked);

      \__ __get_user_pages()

        \__ faultin_page() //如果哪没有分配page,进入缺页处理流程

          \__ handle_mm_fault() //这里就和do_page_faul合流了

3. sys_mmap

通常来说mmap()只会分配一段vma空间,并且记录vma和file的关系,并不会马上进行实质性的映射。分配物理内存page、拷贝文件内容、创建mmu映射的这些后续动作在缺页异常中进行

SYSCALL_DEFINE6(mmap_pgoff, unsigned long, addr, unsigned long, len,

                unsigned long, prot, unsigned long, flags,

                unsigned long, fd, unsigned long, pgoff)

{

        return ksys_mmap_pgoff(addr, len, prot, flags, fd, pgoff);

}

ksys_mmap_pgoff()

\__ vm_mmap_pgoff(file, addr, len, prot, flags, pgoff)

\\__ do_mmap_pgoff()

|  \__do_mmap()

|    \__ mmap_region()

|      |_ vma=vm_area_alloc()

|      |_ vma_link()

  \__ mm_populate()


unsigned long vm_mmap_pgoff(struct file *file, unsigned long addr,

        unsigned long len, unsigned long prot,

        unsigned long flag, unsigned long pgoff)

{     

        unsigned long ret;

        struct mm_struct *mm = current->mm;

        unsigned long populate;

        LIST_HEAD(uf);

        ret = security_mmap_file(file, prot, flag);

        if (!ret) {

                if (mmap_write_lock_killable(mm))

                        return -EINTR;

                ret = do_mmap_pgoff(file, addr, len, prot, flag, pgoff,

                                    &populate, &uf);

                mmap_write_unlock(mm);

                userfaultfd_unmap_complete(mm, &uf);

                if (populate)

                        mm_populate(ret, populate);

        }

        return ret;

}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335

推荐阅读更多精彩内容