C++分配内存的方式:new delete malloc free、placement new 数组new跟delete
程序空间布局管理:这些是站在最理想情况的程序员设计角度来谈的
栈
mmap
堆
BSS
数据段
TEXT段
讲讲malloc
是C库函数,底层会调用brk跟mmap两种系统调用,缺省值是128kb,也就是说小于128kb的时候会默认调用brk,当大于的时候会调用mmap
调用brk是控制堆栈向上生长栈顶移动,释放brk分配的内存,并不会真正立即归还给os,而是等待下次分配空间时有机会对其进行再次利用,避免了开辟这块小空间造成的开销。
为什么不全部利用brk进行分配呢?因为如果之后的操作中都不会再申请这样一块满足小内存要求的空间分配的话,实际内存就会一直生长增大,几十k的碎片空间一直没被利用到,就会越来越大,碎片产生的比较多也就是内存泄露了。而且这种碎片用valgrind还检测不到因为free执行了归还的假象。
调用mmap,则需要先知道linux内存管理是怎样的
linux内存管理一般情况下都是采取页式内存管理,即每个进程的虚拟地址空间是相互隔离的,每个进程都有自己的一套页号分配(虚拟空间分页,物理内存也分页),页表位于进程的内存控制块(Task struct)或者说是PCB(进程控制块上),当执行到某一个虚拟地址获得其数据时,通过这个虚拟地址计算得到的页号以及页内偏移量(页面大小通常为4KB),就可以去查表,如果查到了页号,就能得到其对应的物理页,就可以访问了。实际情况可能更复杂,使用的多级页表+快表查询,加快了速度,减小了内存代价。查找页面的结果有两种情况,缺页或者已经映射到物理内存,对于缺页的情况还要有页面调度算法将其从磁盘swap到内存上才能使用。
mmap是一种内存映射方法,可以将进程的一段虚拟地址和磁盘上的某一个文件在文件系统中的位置建立映射关系,映射结果是得到了指针,操作这个指针对内存进行修改,结果是不要经过正常的read write这些文件io的自动写回。如果从另一个角度看,这个对这个文件修改了,也直接作用内存空间上的数据那么就可以实现线程共享内存。
调用时包括了两个mmap函数。用户mmap库函数在分配时首先要找到一块满足要求的虚拟内存,之后会在内核为进程维护的task struct上配分一个新的vm area struct ,把内容初始化再插入到这个链表结构里。内核mmap函数建立到文件系统的映射。
这种内存分配都是在虚拟内存上进行的,如果不对其访问读取就不会映射真实物理内存,所以第一次要触发缺页,置换swap再通过CPU的MMU内存管理单元映射到物理内存。注:修改的脏页还需要通过msync进行同步,才能保存到文件。
为什么不全部使用brk/mmap进行动态内存分配?
brk直接操作堆顶指针,不涉及到内核操作不需要切换上下文,但是会造成潜在的内存泄露问题内存碎片,mmap切换开销大,粒度更大
mmap要切换用户态内核态。每次分配完了第一次访问都触发缺页,CPU开销高。
free() 函数只传入一个内存地址,为什么能知道要释放多大的内存?
malloc 返回给用户态的内存起始地址比进程的堆空间起始地址多了 16 字节
这个多出来的 16 字节就是保存了该内存块的描述信息,比如有该内存块的大小。
分配的堆空间比想象得命令其分配得要更多几个字节。 什么是用户态什么是内核态 为什么要有用户态跟内核态? 标签:八股,操作系统,映射,mmap,brk,内存,linux,分配,内核 From: https://www.cnblogs.com/synapse331/p/17646496.html