深入理解Linux内存子系统

289次阅读  |  发布于3年以前


导语

linux 内存是后台开发人员,需要深入了解的计算机资源。合理的使用内存,有助于提升机器的性能和稳定性。本文主要介绍 linux 内存组织结构和页面布局,内存碎片产生原因和优化算法,linux 内核几种内存管理的方法,内存使用场景以及内存使用的那些坑。从内存的原理和结构,到内存的算法优化,再到使用场景,去探寻内存管理的机制和奥秘。


目录

一、走进 linux 内存

1、内存是什么?

1)内存又称主存,是 CPU 能直接寻址的存储空间,由半导体器件制成;

2)内存的特点是存取速率快,断电一般不保存数据,非持久化设备;

2、内存的作用

1)暂时存放 cpu 的运算数据

2)硬盘等外部存储器交换的数据

3)保障 cpu 计算的稳定性和高性能!

二、 linux 内存地址空间

1、linux 内存地址空间 Linux 内存管理全貌

2、内存地址——用户态&内核态

3、内存地址——MMU 地址转换

4、内存地址——分段机制

  1. 段选择符
  1. 分段实现

5、内存地址——分页机制(32 位)

6、用户态地址空间

7、内核态地址空间

8、进程内存空间

三、 Linux 内存分配算法

内存管理算法——对讨厌自己管理内存的人来说是天赐的礼物

Linux 内存管理框架

1、内存碎片

  1. 基本原理
  1. 如何避免内存碎片

2、伙伴系统算法——组织结构

  1. 概念
  1. 外部碎片

3、伙伴系统算法——申请和回收

  1. 申请算法
  1. 回收算法

  1. 条件

4、如何分配 4M 以上内存?

  1. 为何限制大块内存分配
  1. 内核中获取 4M 以上大内存的方法

5、伙伴系统——反碎片机制

  1. 不可移动页
  1. 可回收页

6、slab 算法——基本原理

  1. 基本概念
  1. 内部碎片

7、slab 分配器的结构

详细参考: [ 经典|图解Linux内存性能优化核心思想]

8、slab 高速缓存

  1. 普通高速缓存
  1. 专用高速缓存

9、内核态内存池

  1. 基本原理
  1. 内核 API

10、用户态内存池

  1. C++ 实例

11、DMA 内存

  1. 什么是 DMA
  1. DMA 信号

四、 内存使用场景

out of memory 的时代过去了吗?no,内存再充足也不可任性使用。

1、内存的使用场景

2、用户态内存分配函数

a) 如果当前连续内存块足够 realloc 的话,只是将 p 所指向的空间扩大,并返回 p 的指针地址。这个时候 q 和 p 指向的地址是一样的

b) 如果当前连续内存块不够长度,再找一个足够长的地方,分配一块新的内存,q,并将 p 指向的内容 copy 到 q,返回 q。并将 p 所指向的内存空间删除

3 、内核态内存分配函数

4、malloc 申请内存

5、缺页异常

6、用户进程访问内存分析

7、共享内存

  1. 原理

  1. shm 接口

五、 内存使用那些坑

1、C 内存泄露

2、C 野指针

3、C 资源访问冲突

4、STL 迭代器失效

错误示例:删除当前迭代器,迭代器会失效

正确示例:迭代器 erase 时,需保存下一个迭代器

5、C++ 11 智能指针

(1)原理分析:

(2)数据结构:

(3)使用方法:

6、C++ 11 更小更快更安全

六、 如何查看内存


$cat /proc/meminfo
MemTotal:        8052444 kB #所有内存(RAM)大小,减去一些预留空间和内核的大小。
MemFree:         2754588 kB #完全没有用到的物理内存,lowFree+highFree
MemAvailable:    3934252 kB #在不使用交换空间的情况下,启动一个新的应用最大可用内存的大小,计算方式:MemFree+Active(file)+Inactive(file)-(watermark+min(watermark,Active(file)+Inactive(file)/2))
Buffers:          137128 kB #块设备所占用的缓存页,包括:直接读写块设备以及文件系统元数据(metadata),比如superblock使用的缓存页。
Cached:          1948128 kB #表示普通文件数据所占用的缓存页。
SwapCached:            0 kB #swap cache中包含的是被确定要swapping换页,但是尚未写入物理交换区的匿名内存页。那些匿名内存页,比如用户进程malloc申请的内存页是没有关联任何文件的,如果发生swapping换页,这类内存会被写入到交换区。
Active:          3650920 kB #active包含active anon和active file
Inactive:        1343420 kB #inactive包含inactive anon和inactive file
Active(anon):    2913304 kB #anonymous pages(匿名页),用户进程的内存页分为两种:与文件关联的内存页(比如程序文件,数据文件对应的内存页)和与内存无关的内存页(比如进程的堆栈,用malloc申请的内存),前者称为file pages或mapped pages,后者称为匿名页。
Inactive(anon):   727808 kB #见上
Active(file):     737616 kB #见上
Inactive(file):   615612 kB #见上
SwapTotal:       8265724 kB #可用的swap空间的总的大小(swap分区在物理内存不够的情况下,把硬盘空间的一部分释放出来,以供当前程序使用)
SwapFree:        8265724 kB #当前剩余的swap的大小
Dirty:               104 kB #需要写入磁盘的内存去的大小
Writeback:             0 kB #正在被写回的内存区的大小
AnonPages:       2909332 kB #未映射页的内存的大小
Mapped:           815524 kB #设备和文件等映射的大小
Shmem:            732032 kB #共享内存大小
Slab:             153096 kB #内核数据结构slab的大小
SReclaimable:      99684 kB #可回收的slab的大小
SUnreclaim:        53412 kB #不可回收的slab的大小
KernelStack:       14288 kB
PageTables:        62192 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:    12291944 kB
Committed_AS:   11398920 kB
VmallocTotal:   34359738367 kB
VmallocUsed:           0 kB
VmallocChunk:          0 kB
HardwareCorrupted:     0 kB
AnonHugePages:   1380352 kB
CmaTotal:              0 kB
CmaFree:               0 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
DirectMap4k:      201472 kB
DirectMap2M:     5967872 kB
DirectMap1G:     3145728 kB

当前系统的buddy状态可以通过 cat /proc/buddyinfo 命令查看

cat /proc/buddyinfo 
Node 0, zone      DMA     23     15      4      5      2      3      3      2      3      1      0 
Node 0, zone   Normal    149    100     52     33     23      5     32      8     12      2     59 
Node 0, zone  HighMem     11     21     23     49     29     15      8     16     12      2    142 

可以通过 cat /proc/slabinfo 命令查看

cat /proc/slabinfo 
slabinfo - version: 2.1
# name            <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables <limit> <batchcount> <sharedfactor> : slabdata <active_slabs> <num_slabs> <sharedavail>
bridge_fdb_cache       0      0     64   59    1 : tunables  120   60    0 : slabdata      0      0      0
nf_conntrack_expect      0      0    240   16    1 : tunables  120   60    0 : slabdata      0      0      0
nf_conntrack_ffffffff81f6f600      0      0    304   13    1 : tunables   54   27    0 : slabdata      0      0      0
iser_descriptors       0      0    128   30    1 : tunables  120   60    0 : slabdata      0      0      0
ib_mad                 0      0    448    8    1 : tunables   54   27    0 : slabdata      0      0      0
fib6_nodes            22     59     64   59    1 : tunables  120   60    0 : slabdata      1      1      0
ip6_dst_cache         13     24    320   12    1 : tunables   54   27    0 : slabdata      2      2      0
ndisc_cache            1     10    384   10    1 : tunables   54   27    0 : slabdata      1      1      0
ip6_mrt_cache          0      0    128   30    1 : tunables  120   60    0 : slabdata      0      0      0

可以通过 /proc/sys/vm/drop_caches来释放

#To free pagecache, use
echo 1 > /proc/sys/vm/drop_caches
#To free dentries and inodes, use 
echo 2 > /proc/sys/vm/drop_caches
#To free pagecache, dentries and inodes, use
echo 3 >/proc/sys/vm/drop_cache

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8