Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Linux | 内存分配之malloc->brk

Linux | 内存分配之malloc->brk

作者头像
heidsoft
发布于 2023-03-18 09:17:05
发布于 2023-03-18 09:17:05
2K00
代码可运行
举报
运行总次数:0
代码可运行

~/Downloads/research/linux-5.15.4/mm/mmap.c

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SYSCALL_DEFINE1(brk, unsigned long, brk)
{
  unsigned long newbrk, oldbrk, origbrk;
  struct mm_struct *mm = current->mm;
  struct vm_area_struct *next;
  unsigned long min_brk;
  bool populate;
  bool downgraded = false;
  LIST_HEAD(uf);

  if (mmap_write_lock_killable(mm))
    return -EINTR;

  origbrk = mm->brk;

#ifdef CONFIG_COMPAT_BRK
  /*
   * CONFIG_COMPAT_BRK can still be overridden by setting
   * randomize_va_space to 2, which will still cause mm->start_brk
   * to be arbitrarily shifted
   */
  if (current->brk_randomized)
    min_brk = mm->start_brk;
  else
    min_brk = mm->end_data;
#else
  min_brk = mm->start_brk;
#endif
  if (brk < min_brk)
    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))
    goto out;

  newbrk = PAGE_ALIGN(brk);
  oldbrk = PAGE_ALIGN(mm->brk);
  if (oldbrk == newbrk) {
    mm->brk = brk;
    goto success;
  }

  /*
   * Always allow shrinking brk.
   * __do_munmap() may downgrade mmap_lock to read.
   */
  if (brk <= mm->brk) {
    int ret;

    /*
     * mm->brk must to be protected by write mmap_lock so update it
     * before downgrading mmap_lock. When __do_munmap() fails,
     * mm->brk will be restored from origbrk.
     */
    mm->brk = brk;
    ret = __do_munmap(mm, newbrk, oldbrk-newbrk, &uf, true);
    if (ret < 0) {
      mm->brk = origbrk;
      goto out;
    } else if (ret == 1) {
      downgraded = true;
    }
    goto success;
  }

  /* Check against existing mmap mappings. */
  next = find_vma(mm, oldbrk);
  if (next && newbrk + PAGE_SIZE > vm_start_gap(next))
    goto out;

  /* Ok, looks good - let it rip. */
  if (do_brk_flags(oldbrk, newbrk-oldbrk, 0, &uf) < 0)
    goto out;
  mm->brk = brk;

success:
  populate = newbrk > oldbrk && (mm->def_flags & VM_LOCKED) != 0;
  if (downgraded)
    mmap_read_unlock(mm);
  else
    mmap_write_unlock(mm);
  userfaultfd_unmap_complete(mm, &uf);
  if (populate)
    mm_populate(oldbrk, newbrk - oldbrk);
  return brk;

out:
  mmap_write_unlock(mm);
  return origbrk;
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/*
 *  this is really a simplified "do_mmap".  it only handles
 *  anonymous maps.  eventually we may be able to do some
 *  brk-specific accounting here.
 */
static int do_brk_flags(unsigned long addr, unsigned long len, unsigned long flags, struct list_head *uf)
{
  struct mm_struct *mm = current->mm;
  struct vm_area_struct *vma, *prev;
  struct rb_node **rb_link, *rb_parent;
  pgoff_t pgoff = addr >> PAGE_SHIFT;
  int error;
  unsigned long mapped_addr;

  /* Until we need other flags, refuse anything except VM_EXEC. */
  if ((flags & (~VM_EXEC)) != 0)
    return -EINVAL;
  flags |= VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT | mm->def_flags;

  mapped_addr = get_unmapped_area(NULL, addr, len, 0, MAP_FIXED);
  if (IS_ERR_VALUE(mapped_addr))
    return mapped_addr;

  error = mlock_future_check(mm, mm->def_flags, len);
  if (error)
    return error;

  /* Clear old maps, set up prev, rb_link, rb_parent, and uf */
  if (munmap_vma_range(mm, addr, len, &prev, &rb_link, &rb_parent, uf))
    return -ENOMEM;

  /* Check against address space limits *after* clearing old maps... */
  if (!may_expand_vm(mm, flags, len >> PAGE_SHIFT))
    return -ENOMEM;

  if (mm->map_count > sysctl_max_map_count)
    return -ENOMEM;

  if (security_vm_enough_memory_mm(mm, len >> PAGE_SHIFT))
    return -ENOMEM;

  /* Can we just expand an old private anonymous mapping? */
  vma = vma_merge(mm, prev, addr, addr + len, flags,
      NULL, NULL, pgoff, NULL, NULL_VM_UFFD_CTX);
  if (vma)
    goto out;

  /*
   * create a vma struct for an anonymous mapping
   */
  vma = vm_area_alloc(mm);
  if (!vma) {
    vm_unacct_memory(len >> PAGE_SHIFT);
    return -ENOMEM;
  }

  vma_set_anonymous(vma);
  vma->vm_start = addr;
  vma->vm_end = addr + len;
  vma->vm_pgoff = pgoff;
  vma->vm_flags = flags;
  vma->vm_page_prot = vm_get_page_prot(flags);
  vma_link(mm, vma, prev, rb_link, rb_parent);
out:
  perf_event_mmap(vma);
  mm->total_vm += len >> PAGE_SHIFT;
  mm->data_vm += len >> PAGE_SHIFT;
  if (flags & VM_LOCKED)
    mm->locked_vm += (len >> PAGE_SHIFT);
  vma->vm_flags |= VM_SOFTDIRTY;
  return 0;
}
  • https://www.man7.org/linux/man-pages/man2/brk.2.html
  • https://corey.tech/DevOps-Industry-Updates-1/
  • https://jgsun.github.io/2019/01/21/linux-tcpdump/
  • https://zgqallen.github.io/2019/05/14/linux-glic-mm-overview/
  • https://www.freesion.com/article/87121104152/
  • https://codereview.stackexchange.com/questions/80190/malloc-free-realloc-using-brk-and-sbrk
  • https://www.kernel.org/doc/html/latest/core-api/memory-allocation.html
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-11-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 云数智圈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
brk实现
在32位Linux内核中,每个用户进程拥有3GB的虚拟空间。内核如何为用户空间来划分这3GB的虚拟空间呢?用户进程的可执行文件由代码段和数据段组成,数据段包括所有静态分配的数据空间,例如全局变量和静态局部变量等。这些空间在可执行文件装载时,内核就为其分配好这些空间,包括虚拟地址和物理页面,并建立好两者的映射关系。如图2.15所示,用户进程的用户栈从3GB虚拟空间的顶部开始,由顶向下延伸,而brk分配的空间是从数据段的顶部end_data到用户栈的底部。所以动态分配空间是从进程的end_data开始,每次分配一块空间,就把这个边界往上推进一段,同时内核和进程都会记录当前边界的位置。
233333
2020/07/31
9020
brk实现
mmap的系统调用
mmap:进程创建匿名的内存映射,把内存的物理页映射到进程的虚拟地址空间。进程把文件映射到进程的虚拟地址空间,可以像访问内存一样访问文件,不需要调用系统调用read()/write()访问文件,从而避免用户模式和内核模式之间的切换,提高读写文件速度。两个进程针对同一个文件创建共享的内存映射,实现共享内存。2.删除内存映射
刘盼
2023/01/05
1.7K0
mmap的系统调用
【Linux 内核 内存管理】mmap 系统调用源码分析 ⑤ ( mmap_region 函数执行流程 | mmap_region 函数源码 )
调用 mmap 系统调用 , 先检查 " 偏移 " 是否是 " 内存页大小 " 的 " 整数倍 " , 如果偏移是内存页大小的整数倍 , 则调用 sys_mmap_pgoff 函数 , 继续向下执行 ;
韩曙亮
2023/03/30
2K0
【Linux 内核 内存管理】mmap 系统调用源码分析 ⑤ ( mmap_region 函数执行流程 | mmap_region 函数源码 )
一文读懂 Linux 内存分配全过程
在《你真的理解内存分配》一文中,我们介绍了 malloc 申请内存的原理,但其在内核怎么实现的呢?所以,本文主要分析在 Linux 内核中对堆内存分配的实现过程。
用户7686797
2021/05/11
1.7K0
一文读懂 Linux 内存分配全过程
Linux之内存描述符mm_struct
Linux对于内存的管理涉及到非常多的方面,这篇文章首先从对进程虚拟地址空间的管理说起。(所依据的代码是2.6.32.60) 无论是内核线程还是用户进程,对于内核来说,无非都是task_struct这个数据结构的一个实例而已,task_struct被称为进程描述符(process descriptor),因为它记录了这个进程所有的context。其中有一个被称为'内存描述符‘(memory descriptor)的数据结构mm_struct,抽象并描述了Linux视角下管理进程地址空间的所有信息。 mm_s
233333
2018/03/07
2.2K0
Linux之内存描述符mm_struct
Linux内存映射——mmap
所谓的内存映射就是把物理内存映射到进程的地址空间之内,这些应用程序就可以直接使用输入输出的地址空间,从而提高读写的效率。Linux提供了mmap()函数,用来映射物理内存。在驱动程序中,应用程序以设备文件为对象,调用mmap()函数,内核进行内存映射的准备工作,生成vm_area_struct结构体,然后调用设备驱动程序中定义的mmap函数。
全栈程序员站长
2022/07/02
6.4K0
Linux内存映射——mmap
【Linux 内核 内存管理】mmap 系统调用源码分析 ④ ( do_mmap 函数执行流程 | do_mmap 函数源码 )
调用 mmap 系统调用 , 先检查 " 偏移 " 是否是 " 内存页大小 " 的 " 整数倍 " , 如果偏移是内存页大小的整数倍 , 则调用 sys_mmap_pgoff 函数 , 继续向下执行 ;
韩曙亮
2023/03/30
2.3K0
【Linux 内核 内存管理】mmap 系统调用源码分析 ④ ( do_mmap 函数执行流程 | do_mmap 函数源码 )
聊聊跨进程共享内存的内部工作原理
在 Linux 系统的进程虚拟内存中,一个重要的特性就是不同进程的地址空间是隔离的。A 进程的地址 0x4000 和 B 进程的 0x4000 之间没有任何关系。这样确确实实是让各个进程的运行时互相之间的影响降到了最低。某个进程有 bug 也只能自己崩溃,不会影响其它进程的运行。
开发内功修炼
2023/12/11
1K0
聊聊跨进程共享内存的内部工作原理
Linux进程的内存管理之malloc和mmap
通过《Linxu进程的内存管理》,我们知道了进程内存的最小单位是vma,根据不同的用处又划分了不同类型的vma,比如
刘盼
2021/03/23
5.4K0
Linux mmap原理
mmap是linux操作系统提供给用户空间调用的内存映射函数,很多人仅仅只是知道可以通过mmap完成进程间的内存共享和减少用户态到内核态的数据拷贝次数,但是并没有深入理解mmap在操作系统内部是如何实现的,原理是什么。
大忽悠爱学习
2022/10/30
4.1K0
Linux mmap原理
从内核世界透视 mmap 内存映射的本质(源码实现篇)
本文我们将进入到内核源码实现中,来看一下虚拟内存分配的过程,在这个过程中,我们还可以亲眼看到前面介绍的 mmap 内存映射原理在内核中具体是如何实现的,下面我们就从 mmap 系统调用的入口处来开始本文的内容:
bin的技术小屋
2023/10/30
8340
从内核世界透视 mmap 内存映射的本质(源码实现篇)
Linux虚拟内存管理
Linux的内存管理分为 虚拟内存管理 和 物理内存管理,本文主要介绍 虚拟内存管理 的原理和实现。在介绍 虚拟内存管理 前,首先介绍一下 x86 CPU 内存寻址的具体过程。
用户7686797
2020/08/25
4.4K0
Linux虚拟内存管理
【Linux 内核 内存管理】munmap 系统调用源码分析 ② ( do_munmap 函数执行流程 | do_munmap 函数源码 )
munmap 系统调用函数 调用了 vm_munmap 函数 , 在 vm_munmap 函数 中 , 又调用了 do_munmap 函数 , do_munmap 函数 是 删除 内存映射 的 核心函数 ;
韩曙亮
2023/03/30
8520
【Linux 内核 内存管理】munmap 系统调用源码分析 ② ( do_munmap 函数执行流程 | do_munmap 函数源码 )
一文聊透 Linux 缺页异常的处理 —— 图解 Page Faults
在前面两篇介绍 mmap 的文章中,笔者分别从原理角度以及源码实现角度带着大家深入到内核世界深度揭秘了 mmap 内存映射的本质。从整个 mmap 映射的过程可以看出,内核只是在进程的虚拟地址空间中寻找出一段空闲的虚拟内存区域 vma 然后分配给本次映射而已。
bin的技术小屋
2023/12/21
4.3K0
一文聊透 Linux 缺页异常的处理 —— 图解 Page Faults
Linux进程的内存管理
一个进程的虚拟地址空间主要由两个数据结来描述,一个是 mm_struct,一个是 vm_area_structs。
刘盼
2021/03/23
3.6K0
完全剖析 - Linux虚拟内存空间管理
在 《漫画解说内存映射》一文中介绍过 虚拟内存 与 物理内存 映射的原理与过程,虚拟内存与物理内存进行映射的过程被称为 内存映射。内存映射是硬件(内存管理单元)级别的功能,必须按照硬件的规范设置好内存映射的关系,进程才能正常运行。
用户7686797
2021/06/15
3.5K0
完全剖析 - Linux虚拟内存空间管理
linux内核缺页中断处理
现代处理器大部分都有MMU,除了一些小型嵌入式设备。MMU可以做虚拟地址到物理地址的转换,使用MMU我们就可以使用更多的内存空间,因为程序具有局部性原理,我们可以将暂时用不到的数据存放到磁盘,当访问到时会发生缺页中断,从磁盘中将所需要的数据加载到内存。所以我们可以通过mmu运行程序大小大于内存的程序和打开大于内存的文件。现代处理器通过分段分页机制实现虚拟地址到物理地址转换一般支持二级页表或四级页表。
用户4415180
2022/06/23
11.5K0
linux内核缺页中断处理
转让malloc()该功能后,发生了什么事内核?附malloc()和free()实现源
特此声明:在本文中,引用另一篇文章和帖子,结合的概括的理解malloc()函数的实现机制。
全栈程序员站长
2022/07/06
3780
Linux内存管理2.6 -反向映射RMAP(最终版本)
所谓反向映射是相对于从虚拟地址到物理地址的映射,反向映射是从物理页面到虚拟地址空间VMA的反向映射。
233333
2023/08/14
7300
Linux内存管理2.6 -反向映射RMAP(最终版本)
内存页面共享-KSM
本文适合有基本Linux内存管理概念的新手阅读,且本文旨在从工作流程和设计思想上介绍KSM,在涉及到源代码的地方,进行了部分删减,如果想详细了解KSM,推荐阅读源代码及源代码中的注释。
233333
2020/08/28
2.3K0
相关推荐
brk实现
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验