内存管理介绍

内存管理介绍node


.内存管理介绍:ios


1.内存分页技术 【Paging算法

 

@内存被分为一页一页的,对于x86的系统,每一页的大小通常是4 KiB (4096 Bytes)数组

@每个进程不是直接对内存进行存储的,而是每个进程都会被分配一个虚存地址空间【virtual address space缓存

———对于32位的系统来讲:每一个进程最大能够有4 GiB的虚存空间。大数据

【这个是过去的事情了,RedHat 4的就能够访问64GiB的内存,可是你虚存空间仍是4GiBspa

【你们可能会有疑问,32位系统最多能访问2^32/2^30=4 GiB的空间,怎么能处理16GiB的空间呢?缘由是CPU有一个PAE【物理地址扩展】,它能够帮助咱们在原来的物理寻址的基础上再增长4位,2^(32+4)/2^30=64GiBserver

———对于64位的系统来讲:每一个进程最大能够有16 EiB的虚存空间。队列


@你的进程看见的都是虚拟的内存,若是物理内存小于虚存空间的时候,而你的进程又已经使用大于你的物理内存的大小的时候,进程就开始和你的硬盘交互(swap)。进程


@一个真的物理内存的咱们称为Page Frame[页帧],一个虚拟内存咱们称为Page[]


@不一样进程能够共享同一片真实内存区域(只要内核容许)。虚拟内存到真实内存的转换是有必定的算法的。



2.Page Walk

@进程在运行时往虚拟内存里面写数据,这部分数据就在真实内存的页表【Page Table】里面存着,一个页表是4KiB


@在下一次存储的时候,进程都会先去找到那些页表的位置,这个动做就叫Page Walk。这个动做由硬件支持,可是仍是相对比较慢【相对CPU的计算而言】,通常来讲它须要

10100CPU的时钟周期。关键看你的缓存了,若是缓存【一,二缓存】中有,就直接从缓存中拿,那固然快。


这是一个Page Walk须要作的步骤,4层结构。

从左往右分别是:全局树,上层树,中间树,页表【每一个页表记录了一个内存的真实地址】。



3.CPUTLB缓存

@因为Page Walk很耗时间,重复跑对CPU伤害很大。因此CPU有一个TLB缓存。当进程开始写的时候,会如今TLB缓存里面找有没有相应的映射关系,若是有就是命中,直接返回就不走Page Walk。若是没有映射关系,则TLB还得回答,你要找的地址如今内存中分好了有没有,若是有,则直接去存,而后创建映射关系。若是没有分好,【技术上叫这个动做为Page Fault】则如今现分一个。


@[root@instructor 442]# x86info -c 能够查看有关TLB大小的信息。

...

TLB info

Data TLB: 4KB pages, 4-way associative, 64 entries #只有64个入口,因此这部发资源竞争确定很大。

...

@TLB里面的数据只要有上下文切换【换另外一个进程来执行】的时候都会被刷新【什么都没了】。

下面的命令能够看出,就算我CPU很闲,每秒都有40几回的上下文切换:

[root@instructor 442]# vmstat

procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----

r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st

0  0      0 6389132 113208 859244    0    0    10     5   18   42 0  0 99  1



4.内存大页技术


案例:

对于16GiBOracleSGA它共有1000多个进程。若是用默认的4 KiB每页的形式存储,则大概须要400万的页面来存储。而为了描述这400万个页面的分配地址空间,你所需的页表的大小也将近16 GiB 1000个进程)。这明显不划算,并且TLB最多只有1024个入口。因此,这时候咱们就须要调大每一页的大小,这个就称为大页技术。


@通常来讲对于x86系统,通常大页的每一页是2M,也有4M的。对于2M而言,2M=512*4K,即512倍,这样存储大数据的时候对于所需页表就少了。


@可是这样也有缺点,单位大的时候,有些大页实际上没有被占满,因此浪费也会有所增长,可是处理大数据的时候有明显的提高。

如:上面的Oracle的例子,若是是用2M大页:

16 * 1024 / 2 = 8192个页面就能存储完。对于原来的400万的页面来讲,是一个明显提升。

所需的页表【Page Table】大小:大约为30MiB【也是一个大的突破】


.启动大页技术


1.手动分配大页

@大页都是连续的,因此手动分配的时候,它会从你的内存中找到一连串连续的地址,进行分配。因此,虽然有时候内存够,可是分不出来,就是由于没有那么多连续的地址。


查看当前的大页个数:

[root@server6 ~]# grep Huge /proc/meminfo

AnonHugePages:      2048 kB

HugePages_Total:       0

HugePages_Free:        0

HugePages_Rsvd:        0

HugePages_Surp:        0

Hugepagesize:       2048 kB


分配大页:

[root@server6 ~]# sysctl vm.nr_hugepages=10

vm.nr_hugepages = 10

[root@server6 ~]# grep Huge /proc/meminfo

AnonHugePages:      2048 kB

HugePages_Total:      10

HugePages_Free:       10

HugePages_Rsvd:        0

HugePages_Surp:        0

Hugepagesize:       2048 kB


这个状况就是内存没有太多连续的时候:

[root@server6 ~]# sysctl vm.nr_hugepages=10000

vm.nr_hugepages = 10000

[root@server6 ~]# grep Huge /proc/meminfo

AnonHugePages:         0 kB

HugePages_Total:     415

HugePages_Free:      415

HugePages_Rsvd:        0

HugePages_Surp:        0

Hugepagesize:       2048 kB


【还有一个办法是绝对能够分小于内存大小的大页总数的,写进grub里,开机自动分】


2.使用大页:


@.大页的文件系统

mount -t hugetlbfs  none /mountpoint

以后应用程序用mmap这个系统调用来使用这个/mountpoint


@大页共享内存

应用程序用shmgetshmat这两个系统调用这片共享内存【适用Oracle



@Red Hat企业版6.2以前,所分的大页所占的内存不能被其余不用大页的进程使用。可是,6.2以后,就出了一个透明式的大页使用【简称:THP】。这个在程序调用的时候有时候直接给你一个大页,而后它会在后台自动为你拼装,并且内存不够的时候还能够对把大页劈开进行交换。进程不用管,直接调用内存就行。THP尽量使用大页,你把大页分好就行。


@若是你不想使用THP,能够在内核里面添加一个参数:transparent_hugepages=never


3.Buffer Cache Page Cache的区别

Buffer Cache(Slab cache):用来缓存文件的(dentries and inodes等等)

Page Cache:完彻底全是缓存文件的内容


echo n > /proc/sys/vm/drop_caches

n:[清空]

——1 block data [page cache]

——2 meta data [buffer cache]

——3 block and meta data


.Swap管理


@在咱们添加swap分区以后,若是不带优先级,每添加一个分区它的优先级都比前面的低一点。


@若是加交换分区的时候,若是几个swap分区优先级同样,那么swap分区就会被论寻使用。


内存的状态:

1.Free: 空闲

2.Inactive Clean : 数据已经写如磁盘,且从磁盘读出来后一直没有变化。

3.Inactive Dirty : 这部分没有被使用,可是有数据还没来的即存盘。

4.Active : 正在被使用。


@之前的Kernel[企业版6之前]是使用pdflush来控制这个数据集中写盘的操做。企业版6以后每个磁盘都用per-BDI flush来控制写盘。在IO很是重的时候,你会在ps命令下看到:flush-MAJOR【主号】:MINOR【从号】。


@ 下面是针对脏页的4个可调参数:

这个是指脏页闲置多久以后开始写盘:

vm.dirty_expire_centisecs

这个是指多久内核去检测有没有脏页:

vm.dirty_writeback_centisecs


这个是(默认是10%)当内存有多少脏页的时候开始写盘:

vm.dirty_background_ratio(default 10)


这个内存中有多少脏页的时候,内核开始写盘,直到脏页到10%左右:

ratios的值较低的时候适合交互式业务。较高的时候适合吞吐量大的业务】

vm.dirty_ratio(default 40)



@Out of Memory(OOM)

【当虚存内存准备被使用,而内存却已经不够的时候的状况】

这时候,内核就开始随机杀进程,这个很是危险。因此,咱们更倾向曲,一旦发生OOM,就让整个系统挂起:vm.panic_on_oom = 1 【这个参数就是当有OOM的时候让整个系统挂起】


@内存有分不少区域,不少时候看起来你系统还有内存可是已经发生了OOM,这颇有多是因为低端内存不够形成的。低端内存像:DMADMA32等等。


@内存的结构:


.内存的供应控制


vm.overcommit_memory

【这个是提供虚存的策略】

0:虽然内存会自动识别给不给,可是基本是有多少给多少,就算超过自身物理内存也行。 【默认值】

1:永远容许,要多少都给。

2:不容许提供超过自身物理内存大小的内存。

【这个是可控的:swap+物理内存(vm.overcommit_ratio控制)【默认是50%】】

例:

[root@server6 ~]# sysctl -a | grep overcommit

vm.overcommit_memory = 0

vm.overcommit_ratio = 50

vm.nr_overcommit_hugepages = 0

[root@server6 ~]# sysctl -e vm.overcommit_memory=2


[root@server6 ~]# grep Com /proc/meminfo

CommitLimit:     1526000 kB

Committed_AS:      62236 kB 【这个是虚存的大小】



ipcs 能够查看相关的信号令,消息队列,共享内存的使用量。

ipcs -l 能够查看信号令,消息队列,共享内存的限制


共享内存:

kernel.shmmni:全局你能够申请多少个共享内存段

kernel.shmmax:每一个共享内存段你能够申请的最大值

kernel.shmall:全局上面两个的乘积最大不能超过多少页【单位是页】


信号令:

[root@server6 ~]# sysctl -a | grep kernel.sem

kernel.sem = 250 32000 32 128

A.250:每一个信号令数组中信号令的个数

B.32000:整个系统最多有多少个信号令存在

C.32:每一个信号令能发出去的system call的个数

D.128:信号令数组的个数 【A*D > B是没有意义的】



消息队列:

[root@server6 ~]# sysctl -a | grep kernel.msgmnb

kernel.msgmnb = 65536


kernel.msgmnb:一个消息队列能发多少字节即消息队列的长度

kernel.msgmni:一个消息队列在系统中的个数,这个与内存相关,是个随机数

kernel.msgmax:一个消息能占多少字节

相关文章
相关标签/搜索