malloc分配在哪_malloc能分配多大内存

malloc分配在哪_malloc能分配多大内存动态分配内存函数malloc 和mmap从操作系统角度来看,进程分配内存有两种方式,分别由两个系统调用完成:brk 和 mmap(不考虑共享内存)。brk 的实现方式是将 Data Segment 的最高地址指针 _edata 往高地址推(分配的内存小于 128k )。m

动态分配内存函数malloc 和mmap   从操作系统角度来看,进程分配内存有两种方式,分别由两个系统调用完成:brk 和 mmap(不考虑共享内存)。brk 的实现方式是将 Data Segment 的最高地址指针 _edata 往高地址推(分配的内存小于 128k )。mmap 的实现方式是在 Memory Mapping Segment 找一块空闲的虚拟内存(分配的内存大于 128k )。   (Data segment 和 Memory Mapping Segment 的相关内容查看这里。)   原文地址:https://blog.csdn.net/itworld123/article/details/   布局图   
malloc分配在哪_malloc能分配多大内存
malloc分配在哪_malloc能分配多大内存   说明   名称存储内容stack局部变量、函数参数、返回地址等。heap动态分配的内存。bss未初始化 或 初值为0 的全局变量和静态局部变量。data已初始化 且 初值非0 的全局变量和静态局部变量。text可执行代码、字符串字面值、只读变量。reserved不可访问,用于捕捉使用空指针和小整型值指针引用内存的异常情况。Random stack offsetRandom mmap offsetRandom brk offset意在防止恶意程序。Linux通过对栈、内存映射段、堆的起始地址加上随机偏移量来打乱布局,以免恶意程序通过计算访问栈、库函数等地址。mmap磁盘上的文件映射到虚拟地址空间中,用于装载动态共享库。   拓展   1、分段的好处。   拓展   1、分段的好处。进程运行过程中,代码指令根据流程依次执行,只需访问一次(当然跳转和递归可能使代码执行多次);而数据(数据段和BSS段)通常需要访问多次,因此单独开辟空间以方便访问和节约空间。当程序被装载后,数据和指令分别映射到两个虚存区域。数据区对于进程而言可读写,而指令区对于进程只读。两区的权限可分别设置为可读写和只读。以防止程序指令被有意或无意地改写。现代CPU具有极为强大的缓存(Cache)体系,程序必须尽量提高缓存命中率。指令区和数据区的分离有利于提高程序的局部性。当系统中运行多个该程序的副本时,其指令相同,故内存中只须保存一份该程序的指令部分。若系统中运行数百进程,通过共享指令将节省大量空间(尤其对于有动态链接的系统)。其他只读数据如程序里的图标、图片、文本等资源也可共享。而每个副本进程的数据区域不同,它们是进程私有的。临时数据及需要再次使用的代码在运行时放入栈区中,生命周期短。全局数据和静态数据可能在整个程序执行过程中都需要访问,因此单独存储管理。堆区由用户自由分配,以便管理。   虚拟地址和物理地址映射原理   由于应用程序使用的内存地址是虚拟地址,为了能够将其与实际的物理内存达成一个映射,就需要一个表将虚拟地址映射到实际的物理内存地址,这个表就叫做页表,是存储在主存(RAM)里的。页表中的素就叫做页表项,即虚拟地址与物理地址的映射,具体一点,我们直接看图,以区分开页表、页表项、虚拟地址与物理地址:   
malloc分配在哪_malloc能分配多大内存
malloc分配在哪_malloc能分配多大内存   虚拟地址:也就是应用看到的内存地址,在本文就是一个 4B(32bit)的地址,分为索引值 VPN(Virtual Page Number)和页面偏移量,页面偏移量位数由页大小(page size)决定,Linux 默认页大小为 4KB,我理解这里的页大小也指的是这页地址所指向的总内存大小,也就是说,一页有 4K 个内存地址(映射),即 2^12,这样的话,同一页的内存只有后面 12 位是变化的,前面 20 位是固定的,如图所示;   物理地址:也就是实际的物理内存地址,和虚拟地址的划分一致,分为 PFN(Page Frame Number)和页面偏移量,页面偏移量同样由页大小决定,在默认的 4KB 页大小下,同样是 12 位的偏移量和 20 位的PFN;   所以说,页表其实就是要 VPN 到 PFN 的映射;   页表:页表存储着的其实是 VPN 到 PFN 的映射,是以 array 的形式连续存储的,所以 VPN 作为索引值是隐含在其中的,无需存储在页表中,只需要知道页表的基地址即可,这点类似数组和其下标的关系。系统根据虚拟地址的 VPN 和页表基地址,即可查到对应的 PFN,而虚拟地址的 page offset 就是对应物理地址的 offset,PFN + offset,就得到了虚拟地址对应的物理地址。   页表项:即页表中存储的素,带有 VPN、PFN 之间的映射关系以及其他信息(是否缺页标志位、保护位、修改位、访问位和高速缓存禁止位…);由于 page size 变化会导致 VPN 和 PFN 的位数发生变化,所以表项大小其实是不确定的,具体情况具体对待;   这两种方式分配的都是虚拟内存,没有分配物理内存。在第一次访问已分配的虚拟地址空间的时候,发生缺页中断,操作系统负责分配物理内存,然后建立虚拟内存和物理内存之间的映射关系。   在标准 C 库中,提供了 malloc / free 函数分配释放内存,这两个函数底层是由 brk,mmap,munmap 这些系统调用实现的。   example 1   1、进程调用 A = malloc ( 30k ) 以后,内存空间如下图所示。malloc 函数会调用 brk 系统调用,将 _edata 指针往高地址推 30K,就完成虚拟内存分配。   你可能会问:只要把_edata + 30K 就完成内存分配了?   事实是这样的,_edata + 30K 只是完成虚拟地址的分配,A 这块内存现在还是没有物理页与之对应的,等到进程第一次读写 A 这块内存的时候,发生缺页中断,这个时候,内核才分配 A 这块内存对应的物理页。也就是说,如果用 malloc 分配了 A 这块内容,然后从来不访问它,那么,A 对应的物理页是不会被分配的。
malloc分配在哪_malloc能分配多大内存
malloc分配在哪_malloc能分配多大内存   example2   进程调用 B = malloc(40K) 以后,内存空间如下图所示。
malloc分配在哪_malloc能分配多大内存
malloc分配在哪_malloc能分配多大内存   example 3   3、当 malloc 分配大于 128k 的内存时,使用 mmap 分配内存。在堆和栈之间找一块空闲内存分配(对应独立内存,而且初始化为 0 )。   这么做的原因是 brk 分配的内存需要等到高地址内存释放以后才能释放(例如,在 B 释放之前,A 是不可能释放的,这就是内存碎片产生的原因,什么时候收缩看下面),而 mmap 分配的内存可以单独释放。,如下图所示,这里分配 200k 。
malloc分配在哪_malloc能分配多大内存
malloc分配在哪_malloc能分配多大内存   example 4   4、进程调用 D = malloc(100k) 以后,内存空间如下图所示。
malloc分配在哪_malloc能分配多大内存
malloc分配在哪_malloc能分配多大内存   example 5   5、进程调用 free(C) 以后,C 对应的虚拟内存和物理内存一起释放。   
malloc分配在哪_malloc能分配多大内存
malloc分配在哪_malloc能分配多大内存   example 6   6、进程调用 free(B) 以后,如下图所示,B 对应的虚拟内存和物理内存都没有释放,因为只有一个 _edata 指针,如果往回推,那么 D 这块内存怎么办呢?当然,B 这块内存是可以重用的,如果这个时候再来一个 40K 的请求,那么 malloc 很可能就将 B 这块内存返回的。
malloc分配在哪_malloc能分配多大内存
malloc分配在哪_malloc能分配多大内存   example 7   7、进程调用 free(D) 以后,如下图所示,B 和 D 连接起来变成一块 140K 的空闲内存。当最高地址空间的空闲内存超过128K(可由 M_TRIM_THRESHOLD 选项调节)时,执行内存紧缩操作(trim)。在上一个步骤 free 的时候,发现最高地址空闲内存超过 128 K,于是内存紧缩,如下图所示。
malloc分配在哪_malloc能分配多大内存
malloc分配在哪_malloc能分配多大内存   2 mmap   了解完 虚拟内存 ,再回过头来讲一下 mmap ,也就是内存映射 。内存映射是将一个虚拟内存区域与一个磁盘上的对象关联起来,以初始化这个虚拟内存区域的内容的过程。   2.1 基础概念   先讲下内存映射里的一些概念。   映射对象类型   虚拟内存区域可以映射以下两种类型的对象:   普通文件:即磁盘文件中的一块 连续 的区域。匿名文件:一个由内核创建的全为 二进制零 的文件。当CPU首次引用此区域时,将以二进制零填充到页表中。共享对象   在上一节 虚拟内存 可得知,系统为每个进程提供了单独的页表,从而也实现了进程间数据访问权限的管理以及数据的保护。但同时,通过内存映射的机制,将对象作为 共享对象 映射到两个进程的虚拟内存亦可实现数据的共享。
malloc分配在哪_malloc能分配多大内存
malloc分配在哪_malloc能分配多大内存   2.2 使用方式   然后先讲下如果我们应该如何通过内存映射的方式来访问文件。mmap() 的函数定义如下:   其中参数的含义分别是:   start: 期望的进程虚拟内存起始位置,填 NULL 时由内核来决定起始位置length: 需要映射的对象字节大小fd: 文件句柄offset: 距离文件开始处的偏移量prot: 映射对象的访问权限,用于可指定是否可读写、执行。flags: 映射对象的类型,例如指定是映射普通文件还是请求二进制零、映射共享对象还是私有的写时复制对象等。前4项地含义可通过下图更直观地了解:
malloc分配在哪_malloc能分配多大内存
malloc分配在哪_malloc能分配多大内存   而在 iOS 开发中,当我们需要的数据类型是 NSData 时,可以更简便地通过调用以下方法   2.3 读取过程   当我们通过 mmap 读取文件时,将经历以下步骤:   在当前用户虚拟内存空间中分配一片 指定映射大小 的虚拟内存区域。将磁盘中的文件映射到这片内存区域,等待后续 按需 进行页面调度。当CPU真正访问数据时,触发 缺页异常 将所需的数据页从磁盘拷贝到物理内存,并将物理页地址记录到页表。进程通过页表得到的物理页地址访问文件数据。
malloc分配在哪_malloc能分配多大内存
malloc分配在哪_malloc能分配多大内存   而作为对比,当通过 标准IO 读取一个文件时,步骤为:   将 完整 的文件从磁盘拷贝到物理内存(内核空间)。将完整文件数据从 内核空间 拷贝到 用户空间 以供进程访问。
malloc分配在哪_malloc能分配多大内存
malloc分配在哪_malloc能分配多大内存   2.4 优劣   通过上面 mmap 与 标准IO 的对比,不难发现调用mmap具有以下的优势:   物理内存占用延后:数据直到真正被使用时才会发生拷贝。物理内存占用减少:对于同一份文件无需在物理内存中存放两份,且文件区被划分成片,缺页异常时只将所需的页拷贝到物理内存。方便实现跨进程数据交互、共享:当映射到虚拟内存的对象被设置为共享对象,则不同进程对映射对象的写操作相互可见。然而也能发现 mmap 存在以下 劣势 :   无法映射变长文件:调用mmap()时需指定要映射的文件位置和需要映射的大小范围。如果需要映射的文件过大,会导致过度占用虚拟内存:在调用mmap()后,虚拟内存空间就创建了,此时虽然不会占用物理内存,但依然会占用虚拟内存。此时可考虑只映射文件中自己需要的部分。由此,当我们需要访问一个比较大的文件,尤其是当我们只需要访问其中的一小部分数据的时候,我们可以尝试通过 mmap 的方式来进行访问,减少由于该文件过大而对物理内存的过度占用。
malloc分配在哪_malloc能分配多大内存
malloc分配在哪_malloc能分配多大内存   Linux C/C++高级全栈开发课程(后端/游戏/嵌入式/高性能网络/存储/基础架构)   更多Linux C/C++高级全栈开发(后端/游戏/嵌入式/高性能网络/存储/基础架构)文章:零声架构师整理了一些学习书籍、视频资料(Linux C/C++ 全栈开发 后端/音视频/游戏/嵌入式/高性能网络/存储/基础架构/安全学习资料、教学视频和学习路线图),有需要的可以自行添加学习交流群: 领取哦!!!

2024最新激活全家桶教程,稳定运行到2099年,请移步至置顶文章:https://sigusoft.com/99576.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。 文章由激活谷谷主-小谷整理,转载请注明出处:https://sigusoft.com/57051.html

(0)
上一篇 2024年 8月 31日 下午1:36
下一篇 2024年 8月 31日 下午1:42

相关推荐

关注微信