Linux内存

内存主要用来存储系统和应用程序的指令、数据、缓存等

物理内存

物理内存也被称为主存,大多数计算机用的主存都是动态随机访问内存(DRAM),只有内核才能直接访问物理内存

进程如何访问内存?
linux内核给每个进程都提供了一个独立的虚拟地址空间,并且这个地址空间是连续的。这样,进程就可以很方便的访问虚拟内存。

虚拟地址空间内部有被分为用户空间和内核空间
在这里插入图片描述
32位的系统内核空间占用1G,剩余的3G时用户空间
64 位系统的内核空间和用户空间都是 128T,分别占据整个内存空间的最高和最低处,剩下的中间部分是未定义的
进程在用户态只能访问用户态的内存,只有进入内核态才能访问内核空间的内存。虽然每个进程的地址空间都包含内核空间,但是这些内核空间实际上都是关联的相同的物理内存。这样进程切换内核态后,就能很方便的访问内核空间的内存。
并不是所有的虚拟内存都会分配物理内存的,只有实际使用的虚拟内存才会分配物理内存,并且分配后的物理内存是通过内存映射来管理的。

内存映射实际上就是将虚拟内存地址映射到物理内存地址。为了完成内存映射,内核为每个进程都维护了一张页表,记录虚拟内存与物理内存的映射关系的。
在这里插入图片描述
页表实际上存储在cpu的内存管理单元MMU中,这样,处理器就可以直接通过硬件找到要访问的内存
而当进程访问的虚拟地址在页表中找不到的时候,系统会产生一个缺页异常,进入内核空间分配物理内存、更新进程页表,最后再返回用户空间,恢复进程运行

TLB实际上就是MMU的高速缓存,由于进程的虚拟地址空间是独立的,所以通过减小进程的切换次数,减少TLB的刷新次数,就可以提高TLB缓存的使用率,进而提高cpu的内存访问性能(也就是如果切换进程的话,TLB中的内容也会被刷新,所以TLB的使用率降低)
MMU并不以字节为单位来管理内存,而是规定一个内存映射的最小单位,也就是页,通常是4KB。这样每次内存映射都需要关联4KB或者4KB的整数倍的内存空间。

由于页表很小就会导致页表项过多,为了管理页表项过多的问题:就有了两种机制:
多级页表和大页
多级页表就是通过一级一级的索引最终找到对应的页
下图前四个都是选择页,最后一个是页内偏移
在这里插入图片描述
而大页就是比普通页更大的内存块

虚拟内存空间分布

![在这里插入图片描述](https://img-blog.csdnimg.cn/6fbdb4dea4104d8eaeefa07036ae5747.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bCP6L6j6bihfg==,size_20,color_FFFFFF,t_70,g_se,x_16

1.只读段:包含代码和常量等
2.数据段:包含全局变量等
3.堆:包含动态分配的内存,从低到高向上增长
4.文件映射段:包含动态库、共享内存等。从高位置向下增长
5.栈:包含局部变量和函数调用的上下文等。栈的大小是固定的,一般8MB

内存分配和回收
malloc()是C标准库提供的内存分配函数。对应到系统调用上有两种实现方式:brk() 和 mmap()
bark(小于128k):通过移动堆顶位置来分配内存,这些内存释放后并不会立即归还系统,而是被缓存起来这样就可以重复使用。(我的理解就是页的内容会被缓存起来)。
bark方式的缓存可以减少缺页异常的发生,提高内存的访问效率。不过,由于这些内存没
有归还系统,在内存工作繁忙时,频繁的内存分配和释放会造成内存碎片。
而大块内存(大于128k)则是直接使用内存映射mmap来分配,也就是在文件映射段中找一块空闲内存分配出去。(也就是重新分配新的内存映射)
mmap()方式分配的内存会在释放时直接归还系统,所以每次mmap都会发生缺页异常,当内存工作繁忙的时候,频繁的内存分配就会导致大量的缺页异常使内核的管理负担增大。这也是 malloc 只对大块内存使用 mmap 的原因。
当进程通过malloc()申请虚拟内存后,系统并不会立即分配物理内存,而是在首次访问的时候,才通过缺页异常陷入内核中分配内存

当这两种调用发生后,其实并没有真正分配内存。这些内存,都只在首次访问时才分配,也就是通过缺页异常进入内核中,再由内核来分配内存。

如果遇到比页还小的对象,就会通过slab分配来管理小内存。你可以把slab看成伙伴系统上的一个缓存,主要作用就是分配和释放内核中的小对象。

内存的回收
1.通过LRU算法回收最近最少使用的内存页面
2.将不常访问的内存通过交换分区直接写入到磁盘中,swap交换只有在内存严重不足的情况下才会发生,并且由于磁盘的读写慢于内存,所以swap交换有严重的性能问题
3.通过OOM杀死进程

$ free 
     total   used    free    shared  buff/cache available 
Mem: 8169348 263524  6875352 668     1030472    7611064
Swap: 0 0 0

Mem均指的是物理内存
used 是已使用内存大小,包含共享内存
buff/cache 是缓存或者缓存区
available 是为使用的内存+回收的缓存(并不是所有缓存均是可回收的,即SReclaimable)

top按M会切换到内存排序
在这里插入图片描述
VIRT:进程虚拟内存的大小,只要是进程申请过的内存,即便没有分配真正的物理内存也算在内
RES:常驻内存的大小,也就是进程实际使用的物理内存的大小,但不包含swap和共享内存
SHR:共享内存的大小,比如与其他进程共同使用的共享内存、动态链接库和程序的代码段等
%MEM:进程使用的物理内存占系统总内存的百分比

共享内存 SHR 并不一定是共享的,比方说,程序的代码段、非共享的动态链接库,
也都算在 SHR 里。当然,SHR 也包括了进程间真正共享的内存。所以在计算多个进程的
内存使用时,不要把所有进程的 SHR 直接相加得出结果

缓存和缓冲区

Buffers是缓存读写磁盘的数据

Cache是内核页缓存和slab用到的内存 即 Cached+SReclaimable
页缓存(Cached)是缓存读写文件的数据
slab分为两个部分:SReclaimable(可回收部分)+SUnreclaim(不可回收部分)

工具:
cachestat:提供整个操作系统缓存读写命中情况
cachetop:提供了每个进程缓存命中情况
pcstat /bin/ls:查看/bin/ls文件的缓存情况在这里插入图片描述
Cached:是缓存的大小
Percent:缓存的百分比

查看页缓存和可回收Slab的大小:cat /proc/meminfo | grep -E “SReclaimable|Cached”
在这里插入图片描述

查看系统调用:strace -p pid

内存泄露

栈内存由系统自动分配和管理,一旦程序超过这个局部变量的作用域,栈内存就会被系统自动回收,所以不会出现内存泄漏问题
堆内存由应用程序自己来分配和管理,除非程序退出,否则这些堆内存不会被系统自动释放,而是需要应用程序调用库函数free()来释放它们。如果应用程序没有正确释放它们就会出现内存泄漏
只读段由于是只读的,不会分配新的内存,所以不会存在内存泄漏
数据段包括全局变量和静态变量,这些变量在定义时就已经确定了大小,所以也不会
产生内存泄漏。
内存映射段,包括动态链接库和共享内存,其中共享内存由程序动态分配和管理。所以,如果程序在分配后忘了回收,就会导致跟堆内存类似的泄漏问题
查看内存泄漏的工具:memleak

swap分区

内存回收就是系统释放掉可以回收的内存,比如我们前面讲的缓存和缓冲区就是可回收内存。在内存管理中通常被叫做文件页。
文件页还包含通过内存映射获取的文件映射页
大部分文件页都是可以直接回收的,以后有需要再直接从磁盘中读取就可以了。而那些被应用程序修改过,并且暂时没有写入磁盘的数据(脏页),就得先写入磁盘,然后再进行内存释放
这些脏页有两种方式写入磁盘:
1.可以在应用程序中通过系统调用fsync,把脏页同步到磁盘中
2.也可以交给系统由内核线程pdflush负责这些脏页的刷新

直接内存回收:有新的大块内存分配请求,但是剩余内存不足。这个时候系
统就需要回收一部分内存(比如前面提到的缓存),进而尽可能地满足新内存请求
除了直接内存回收外,还有一个专门的内核定期回收内存,叫作kswapd0
为了衡量内存使用情况,kswapd0定义了三个内存阀值:
在这里插入图片描述
swappiness
内存回收机制即包含了文件页也包含了匿名页
匿名页:指那些没有关联到文件页,如进程堆、栈、数据段和任务已修改的共享库等,不是以文件形式存在,因此无法和磁盘文件交换
对于文件页的回收就是直接回收缓存,或者把脏页写回磁盘再回收
对于匿名页的回收就是通过swap机制,把它们写回磁盘后再释放内存

OOM触发的时机:
oom触发的时机是基于虚拟内存的。换句话说,进程在申请内存时,如果申请的虚拟内存加上服务器实际已用的内存之和大于总的物理内存就会触发OOM

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值