当前位置:2019年全年资料内部公开 > 缺页中断 >

内存分配的原理

  虚拟地址空间如何分布_malloc和free是如何分配和释放内存_如何查看堆内内存的碎片情况_既然堆内内存brk和sbrk不能直接释放,为什么不全部使用 mmap 来分配,munmap直接释放呢

  在使用mysql作为DB开发的兑换券系统中,随着分区表的不断创建,发现mysqld出现了疑似“内存泄露”现象,但通过 valgrind

  等工具检测后,并没发现类似的问题(最终原因是由于glibc的内存碎片造成)。

  1、每个进程都有独立的虚拟地址空间,进程访问的虚拟地址并不是线、虚拟地址可通过每个进程上的页表(在每个进程的内核虚拟地址空间)与物理地址进行映射,获得线、如果虚拟地址对应物理地址不在物理内存中,则产生缺页中断,真正分配物理地址,同时更新进程的页表;如果此时物理内存已耗尽,则根据内存替换算法淘汰部分页面至物理磁盘中。

  一、Linux 虚拟地址空间如何分布?Linux使用虚拟地址空间,大大增加了进程的寻址空间,由低地址到高地址分别为

  该部分空间只能读,不可写;(包括:代码段、rodata段(C常量字符串和#define定义的常量))

  就是平时所说的动态内存, malloc/new大部分都来源于此。其中堆顶的位置可通过函数 brk 和 sbrk 进行动态调整。4、文件映射区域 :

  如动态库、共享内存等映射物理空间的内存,一般是mmap函数所分配的虚拟地址空间。

  用于维护函数调用的上下文空间,一般为 8M ,可通过 ulimit –s 查看。6、内核虚拟空间:

  用户代码不可见的内存区域,由内核管理(页表就存放在内核虚拟空间)。下图是32 位系统典型的虚拟地址空间分布(来自《深入理解计算机系统》)。

  其中 0x08048000~0xbfffffff是用户空间,0xc0000000~0xffffffff是内核空间,包括内核代码和数据、与进程相关的数据结构(如页表、内核栈)等。另外,

  执行栈顶,往低地址方向变化;brk/sbrk 函数控制堆顶_edata往高地址方向变化。

  glibc 提供了以下结构和接口来查看堆内内存和 mmap 的使用情况。

  为指针数组每个成员分配索引位置 (KB)大小的内存块,并通过 128 为分界分别对 heap 和 mmap 内存分配情况进行计数;第二个循环

  是 free索引下标为奇数的项,同时更新计数情况。通过程序的计数与mallinfo/malloc_stats 接口得到结果进行对比,并通过 print_info打印到终端。

  这些值表示不同大小区间的碎片总个数,这些区间分别是 0~80 字节,80~512字节,512~128k

  。如果 fsmblks 、 smblks 的值过大,那碎片问题可能比较严重了。不过,

  mallinfo 结构有一个很致命的问题,就是其成员定义全部都是 int ,在 64 位环境中,其结构中的uordblks/fordblks/arena/usmblks 很容易就会导致溢出,应该是历史遗留问题,使用时要注意!

  四、既然堆内内存brk和sbrk不能直接释放,为什么不全部使用 mmap

  来分配,munmap直接释放呢?既然堆内碎片不能直接释放,导致疑似“内存泄露”问题,为什么

  1M 空间,第一次调用产生了大量缺页中断 (1M/4K 次 ) ,当munmap 后再次分配 1M 空间,会再次产生大量缺页中断。

  另外,如果使用 mmap分配小内存,会导致地址空间的分片更多,内核的管理负担更大。同时堆是一个连续空间,并且堆内碎片由于没有归还 OS

  ,如果可重用碎片,再次访问该内存很可能不需产生任何系统调用和缺页中断,这将大大降低 CPU 的消耗

  。 因此, glibc 的malloc 实现中,充分考虑了 sbrk 和 mmap 行为上的差异及优缺点,默认分配大块内存 (128k) 才使用 mmap 获得地址空间,也可通过

  网上有很多资源,可以自己查(只用使用第三方库,代码不用修改,就可以使用第三方库中的malloc

http://boardflip.com/queyezhongduan/257.html
点击次数:??更新时间2019-06-11??【打印此页】??【关闭
  • Copyright © 2002-2017 DEDECMS. 织梦科技 版权所有  
  • 点击这里给我发消息
在线交流 
客服咨询
【我们的专业】
【效果的保证】
【百度百科】
【因为有我】
【所以精彩】