内存映射中最重要的是页表,页表除了找到虚地址对应的物理地址外,在对应这一行中还存有两个标志位,一个是RWX标志位,表明该位置是可读还是可写,另一个是u/k标志位,区分用户空间和内核空间。每个进程看到4G内存,一般3G-4G虚地址对应kernel空间。
总结页表两个作用:虚实转换;权限管理。
linux中物理内存页数为物理内存大小/4K,例如1G物理内存,则页数为1G/4K
linux物理内存进行分ZONE,通常分为DMA_ZONE,NORMAL_ZONE,HIGHMEM_ZONE,DMA_ZONE用于DMA设备,由于DMA访问内存地址线少,导致DMA访问内存区域较小,无法进行大内存分配,设定好ZONE后确保DMA不会因内存分配过大导致出错。
NORMAL_ZONE和DMA_ZONE位于0-896M,映射到linux的内核空间。
在每个ZONE内部,执行buddy算法,每次将2^n个连续的内存放在一起,查看如图
所以linux中申请页函数alloc_pages(order)是申请2^order页数
这种情况会导致碎片出现。
在针对内核分配空间时引入slab,slab从buddy那里取得内存后,切分为大小一样的小块,例如8字节,16字节等,然后进行分配。实现如下的二级管理机制:
通过slabtop可以对slab进行检测,可作为内存泄漏观察点
linux内存分配为lazy allocation demanding page方式,刚申请时给的是零化空间,随着访问不断分配内存
如图所示,上面为写的部分分配内存成功,没有写的部分依然指向零化页面。
OOM机制是在linux上当内存使用枯竭时,找出最该杀的进程进行kill,从而释放内存。
决定一个进程是否该杀是根据oom_score.
可通过echo [-15,15] > /proc/pidof/oom_adj 设置一个进程的oom_score。Echo到oom_adj中的值越大,oom_score值也会越大,该进程就更容易被杀。
可通过dmesg查看一个进程被杀的原因。
上图为firefox的oom设置
如果不想启用OOM机制,可以将panic_on_oom设为1,这样内存枯竭时不再杀进程,而是操作系统崩溃
在进程task_struct中含有mm,指向mm_struct,其中包含进程所有的内存。
Vma为进程的虚拟地址空间
通过maps能够看到进程所有的VMA。VMA代表逻辑权限,不代表页表权限,VMA中的逻辑权限决定参考记录进程情况信息,进程发生page fault时参考VMA。
当出现page fault时有下面三种情况
RSS不同于VSS,RSS指驻留在内存条上的内存,属于真实内存。VSS>=RSS,采用lazy allocation技术,只有访问到某段空间时,才会在真实内存条上进行内存分配。
如上图所示,对线程1来说
VSS=1+2+3,表明进程虚拟内存大小
RSS=4+5+6,表明驻留在内存中的大小
PSS=4/3+5/2+6,因为有三个线程共享4,两个线程共享5,PSS表明的是均一化内存消耗,PSS能够反映物理内存如何被进程瓜分
USS=6,进程独占部分
可以通过smem查看进程的uss,pss和rss
也可以通过smem –pie=command smem –bar=command.
检测内存泄漏,可以通过在n个时间点上看uss进行判断,内存泄漏趋势为uss不断变大。
用户进程通过两种方式访问硬盘
一种是直接访问dd,一种是挂载文件系统访问。其中两种方式都会在内存中产生page cache.
圆圈1产生的page cache被称为cached page cache
圆圈2产生的page cache称为buffers page cache
通过free命令可以看到内存使用情况
在第一行used中,包含了kernel使用的内存,app使用的内存以及page cached内存
其中page cached内存可以被回收,所以第二行显示了page cache被回收后的内存使用情况。
释放page cache可用
可以看到buffers和cached都减小了
mmap可以将文件映射到进程虚拟地址空间,*p=mmap(),文件对于程序来说就是一段内存区域,这样就可以通过指针直接操作硬盘上文件
上图中为firefox启动过程中的page cache信息,major page fault对应于操作硬盘,minor page fault不操作硬盘。
一个页面有文件背景,其在硬盘上有对应文件
一个页面没有文件背景,通常为程序栈、堆、数据段内容,硬盘上没有对应文件,称为匿名页,常驻内存。
为了不让匿名页常驻内存,也能够被交换出去,linux中为匿名页伪造了文件背景,存放在swap分区(硬盘虚拟分区)
对应关系如下:
Swap替换算法采用LRU,和cache替换算法一样。
在gcc 4.9版本以后,增加了内存泄漏检查工具
Gcc –fsanitize=address