我是靠谱客的博主 俭朴天空,最近开发中收集的这篇文章主要介绍Linux内存布局、内存分配原理Linux的虚拟内存管理有几个关键概念Linux进程虚拟地址分布malloc是如何分配内存的?malloc分配多大的内存,就占用多大的物理内存空间吗?如何查看进程虚拟地址空间的使用情况?free的内存真的释放了?程序代码中malloc的内存都有相应的free,就不会出现内存泄露了吗?既然堆内内存不能直接释放,为什么不全部使用mmap来分配?如何查看进程的缺页中断信息?如何查看堆内内存的碎片情况除了glibc的malloc/free,还有其他第三方实现吗?,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

Linux的虚拟内存管理有几个关键概念

 

1.每个进程有独立的虚拟地址空间,进程访问的虚拟地址并不是真正的物理地址

 

2.虚拟地址可通过每个进程的页表与物理地址进行映射,获得真正物理地址

 

3.如果虚拟地址对应的物理地址不在物理内存中,则产生缺页中断,并真正分配物理地址,同时更新进程的页表;如果此时物理内存已耗尽,则根据内存替换算法淘汰部分页面至物理磁盘中。

 

 

Linux进程虚拟地址分布

 

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

 

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

 

数据段保存全局变量、静态变量的空间

 

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

 

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

 

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

 

内核虚拟空间:用户代码不可见的内存区域,由内核管理。 

32位系统有4G的地址空间,其中0x08048000~0xbfffffff 是用户空间,0xc0000000~0xffffffff是内核空间,包括内核代码和数据、与进程相关的数据结构(如页表、内核栈等)。

 

64位Linux一般使用48位来表示虚拟地址空间,40位表示物理地址,这可通过 /proc/cpuinfo 来查看

address sizes   : 40 bits physical, 48 bits virtual

 

 

malloc是如何分配内存的?

 

malloc是glibc中内存分配函数,也是最常用的动态内存分配函数,其内存必须通过free进行释放,否则导致内存泄露。关于 malloc 获得虚存空间的实现,与glibc的版本有关,但大体逻辑是:

 

1.申请128k以内的内存,调用sbrk(),在堆内分配,将堆顶指针向高地址移动,获得新的虚存空间。虚拟地址比较小。

 

2.每次分配的内存地址前16字节(64位系统,32位是8字节)是记录该内存块的控制信息(用于 free )。

 

3.并不是每次malloc都会导致堆顶的增大,如果堆内有足够剩余空间,堆顶不会发生变化。

 

4.当分配大小大于128k,使用mmap在文件映射区域中分配匿名虚存空间获得地址空间,地址一般比较大(靠近栈区间)

 

5可通过函数mallopt(M_MMAP_THRESHOLD, 64*1024) 修改使用 mmap 的临界值为 64k ,后续大于 64k 的分配就会使用 mmap.

 

 

malloc分配多大的内存,就占用多大的物理内存空间吗?

 

malloc分配的的内存是虚拟地址空间

 

1.VSZ并不是每次malloc后都增长,因为可重用堆顶内剩余的空间,这样的malloc是很轻量快速的。

 

2.如果VSZ发生变化,基本与分配内存量相当,因为VSZ是计算虚拟地址空间总大小。

 

3.RSS的增量很少,是因为malloc分配的内存并不就马上分配实际存储空间,只有第一次使用,发现虚存对应的物理页面未分配,产生缺页中断,才真正分配物理页面,同时更新进程页面的映射关系(按需分配)。

 

4.由于每个物理内存页面大小是4k,不管memset其中的1k还是5k、7k,实际占用物理内存总是4k的倍数。所以RSS的增量总是4k的倍数。

 

 

如何查看进程虚拟地址空间的使用情况?

pmap

 

 

free的内存真的释放了?

 

使用mmap分配的内存会调用munmap系统调用来释放,并会真正释放该空间。

 

free释放内存,在glibc中,仅仅是标记为可用,形成一个内存空洞(碎片),并没有真正释放

 

glibcfree实现中,只要堆顶附近释放总空间(包括合并的空间)超过128k,即会调用sbrk(-SIZE)来回溯堆顶指针,将原堆顶空间还给OS。否则都成为碎片(碎片如果相邻会适当合并)

 

 

程序代码中malloc的内存都有相应的free,就不会出现内存泄露了吗?

 

随着系统频繁地mallocfree,尤其对于小块内存,堆内将产生越来越多不可用的碎片,导致“内存泄露”。而这种“泄露”现象使用valgrind是无法检测出来的。

 

 

既然堆内内存不能直接释放,为什么不全部使用mmap来分配?

 

使用mmap分配1M空间,第一次调用产生了大量缺页中断(1M/4K)。缺页中断是内核行为,会导致内核态CPU消耗较大。

 

堆是一个连续空间,并且堆内碎片由于没有归还OS,如果可重用碎片,再次访问该内存很可能不需产生任何系统调用和缺页中断,这将大大降低CPU的消耗。

 

 

如何查看进程的缺页中断信息?

 

ps -omajflt,minflt -C <program_name>

ps -omajflt,minflt -p <pid>

 

其中majflt表major fault,指大错误。mnflt代表minor fault,指小错误。这两个数值表示一个进程自启动以来所发生的缺页中断的次数。其中majflt与minflt的不同是,majflt表示需要读写磁盘,可能是内存对应页面在磁盘中需要load到物理内存中,也可能是此时物理内存不足,需要淘汰部分物理页面至磁盘中

 

如果进程的内核态CPU使用过多,其中一个原因就可能是单位时间的缺页中断次数多个,可通过以上命令来查看。

 

如果MAJFLT过大,很可能是内存不足。

 

如果MINFLT过大,很可能是频繁分配/释放大块内存(128k),malloc使用mmap来分配。对于这种情况,可通过mallopt(M_MMAP_THRESHOLD, <SIZE>)增大临界值,或程序实现内存池。

 

 

如何查看堆内内存的碎片情况

 

可通过mallinfo结构中的fsmblkssmblksordblks值得到,这些值表示不同大小区间的碎片总个数,这些区间分别是0~80字节,80~512字节,512~128k。如果fsmblks smblks的值过大,那碎片问题可能比较严重了

 

 

除了glibc的malloc/free,还有其他第三方实现吗?

 

googletcmallocfacebookjemalloc

 

最后

以上就是俭朴天空为你收集整理的Linux内存布局、内存分配原理Linux的虚拟内存管理有几个关键概念Linux进程虚拟地址分布malloc是如何分配内存的?malloc分配多大的内存,就占用多大的物理内存空间吗?如何查看进程虚拟地址空间的使用情况?free的内存真的释放了?程序代码中malloc的内存都有相应的free,就不会出现内存泄露了吗?既然堆内内存不能直接释放,为什么不全部使用mmap来分配?如何查看进程的缺页中断信息?如何查看堆内内存的碎片情况除了glibc的malloc/free,还有其他第三方实现吗?的全部内容,希望文章能够帮你解决Linux内存布局、内存分配原理Linux的虚拟内存管理有几个关键概念Linux进程虚拟地址分布malloc是如何分配内存的?malloc分配多大的内存,就占用多大的物理内存空间吗?如何查看进程虚拟地址空间的使用情况?free的内存真的释放了?程序代码中malloc的内存都有相应的free,就不会出现内存泄露了吗?既然堆内内存不能直接释放,为什么不全部使用mmap来分配?如何查看进程的缺页中断信息?如何查看堆内内存的碎片情况除了glibc的malloc/free,还有其他第三方实现吗?所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(28)

评论列表共有 0 条评论

立即
投稿
返回
顶部