內存管理介紹

內存管理介紹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:一個消息能佔多少字節

相關文章
相關標籤/搜索