linux下的緩存機制buffer、cache、swap - 運維總結 ["Cannot allocate memory"問題]


 

一、緩存機制介紹

在Linux系統中,為了提高文件系統性能,內核利用一部分物理內存分配出緩沖區,用於緩存系統操作和數據文件,當內核收到讀寫的請求時,內核先去緩存區找是否有請求的數據,有就直接返回,如果沒有則通過驅動程序直接操作磁盤。
緩存機制優點:減少系統調用次數,降低CPU上下文切換和磁盤訪問頻率。
CPU上下文切換:CPU給每個進程一定的服務時間,當時間片用完后,內核從正在運行的進程中收回處理器,同時把進程當前運行狀態保存下來,然后加載下一個任務,這個過程叫做上下文切換。實質上就是被終止運行進程與待運行進程的進程切換。

Swap用途:Swap意思是交換分區,通常我們說的虛擬內存,是從硬盤中划分出的一個分區。當物理內存不夠用的時候,內核就會釋放緩存區(buffers/cache)里一些長時間不用的程序,然后將這些程序臨時放到Swap中,也就是說如果物理內存和緩存區內存不夠用的時候,才會用到Swap。
swap清理:swapoff -a && swapon -a
注意:這樣清理有個前提條件,空閑的內存必須比已經使用的swap空間大

二、查看緩存區及內存使用情況

對於cpu負載的理解,首先需要搞清楚下面幾個問題:
  
1)系統load高不一定是性能有問題。
因為Load高也許是因為在進行cpu密集型的計算
  
2)系統Load高不一定是CPU能力問題或數量不夠。
因為Load高只是代表需要運行的隊列累計過多了。但隊列中的任務實際可能是耗Cpu的,也可能是耗i/0或者其他因素的。
  
3)系統長期Load高,解決辦法不是一味地首先增加CPU
因為Load只是表象,不是實質。增加CPU個別情況下會臨時看到Load下降,但治標不治本。
  
4)在Load average 高的情況下需要鑒別系統瓶頸到底是CPU不足,還是io不夠快造成或是內存不足造成的。
  
===============================================================================================================
要想獲得服務器的CPU負載情況,有下面幾種命令:
1)w命令
[root@localhost ~]# w
 12:12:41 up 167 days, 20:46,  2 users,  load average: 0.00, 0.01, 0.05
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
root     pts/0    192.168.1.5      10:01    1.00s  0.11s  0.00s w
root     pts/2    192.168.1.5      10:19    1:47m  0.04s  0.04s -bash
   
2)uptime命令(一般首先會根據最后那個15分鍾的load負載為准)
[root@localhost ~]# uptime
 12:12:55 up 167 days, 20:46,  2 users,  load average: 0.00, 0.01, 0.05
   
3)top命令
[root@localhost ~]# top
top - 12:13:22 up 167 days, 20:47,  2 users,  load average: 0.00, 0.01, 0.05
Tasks: 272 total,   1 running, 271 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.0 us,  0.1 sy,  0.0 ni, 99.9 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem : 65759080 total, 58842616 free,   547908 used,  6368556 buff/cache
KiB Swap:  2097148 total,  2097148 free,        0 used. 64264884 avail Mem
................

對於第一行的解釋:
12:13:22:表示當前系統時間
167 days, 20:47:表示系統已經運行了167天20小時47分鍾(在這期間沒有重啟過)
2 users — 當前有2個用戶登錄系統
load average: 0.00, 0.01, 0.05:表示load average后面的三個數分別是1分鍾、5分鍾、15分鍾的負載情況

這里需要注意:
load average數據是每隔5秒鍾檢查一次活躍的進程數,然后按特定算法計算出的數值。
如果這個數除以邏輯CPU的數量,結果高於5的時候就表明系統在超負荷運轉了!!!!!

對上面第三行cpu的狀態的解釋:
us(user cpu time):用戶態使用的cpu時間比。該值較高時,說明用戶進程消耗的 CPU 時間比較多,比如,如果該值長期超過 50%,則需要對程序算法或代碼等進行優化。
sy(system cpu time):系統態使用的cpu時間比。
ni(user nice cpu time):用做nice加權的進程分配的用戶態cpu時間比
id(idle cpu time):空閑的cpu時間比。如果該值持續為0,同時sy是us的兩倍,則通常說明系統則面臨着 CPU 資源的短缺。
wa(io wait cpu time):cpu等待磁盤寫入完成時間。該值較高時,說明IO等待比較嚴重,這可能磁盤大量作隨機訪問造成的,也可能是磁盤性能出現了瓶頸。
hi(hardware irq):硬中斷消耗時間
si(software irq):軟中斷消耗時間
st(steal time):虛擬機偷取時間
  
以上解釋的這些參數的值加起來是100%。
  
4)vmstat
[root@localhost ~]# vmstat
procs -----------memory---------------------swap-------io---------system--------cpu-----
r  b      swpd   free    buff   cache    si   so    bi    bo     in   cs     us sy id wa st
3  0      0      1639792 724280 4854236  0    0     4     34     4    0      19 45 35  0  0
  
解釋說明:
-----------------------------
procs部分的解釋
r 列表示運行和等待cpu時間片的進程數,如果長期大於1,說明cpu不足,需要增加cpu。
b 列表示在等待資源的進程數,比如正在等待I/O、或者內存交換等。
-----------------------------
cpu部分的解釋
us 列顯示了用戶方式下所花費 CPU 時間的百分比。us的值比較高時,說明用戶進程消耗的cpu時間多,但是如果長期大於50%,需要考慮優化用戶的程序。
sy 列顯示了內核進程所花費的cpu時間的百分比。這里us + sy的參考值為80%,如果us+sy 大於 80%說明可能存在CPU不足。
wa 列顯示了IO等待所占用的CPU時間的百分比。這里wa的參考值為30%,如果wa超過30%,說明IO等待嚴重,這可能是磁盤大量隨機訪問造成的,也可能磁盤或者
   磁盤訪問控制器的帶寬瓶頸造成的(主要是塊操作)。
id 列顯示了cpu處在空閑狀態的時間百分比
-----------------------------
system部分的解釋
in 列表示在某一時間間隔中觀測到的每秒設備中斷數。
cs列表示每秒產生的上下文切換次數,如當 cs 比磁盤 I/O 和網絡信息包速率高得多,都應進行進一步調查。
-----------------------------
memory部分的解釋
swpd 切換到內存交換區的內存數量(k表示)。如果swpd的值不為0,或者比較大,比如超過了100m,只要si、so的值長期為0,系統性能還是正常
free 當前的空閑頁面列表中內存數量(k表示)
buff 作為buffer cache的內存數量,一般對塊設備的讀寫才需要緩沖。
cache: 作為page cache的內存數量,一般作為文件系統的cache,如果cache較大,說明用到cache的文件較多,如果此時IO中bi比較小,說明文件系統效率比較好。
-----------------------------
swap部分的解釋
si 由內存進入內存交換區數量。
so由內存交換區進入內存數量。
-----------------------------
IO部分的解釋
bi 從塊設備讀入數據的總量(讀磁盤)(每秒kb)。
bo 塊設備寫入數據的總量(寫磁盤)(每秒kb)
  
  
5)也可以使用dstat命令查看cpu信息
[root@localhost ~]# dstat
----total-cpu-usage---- -dsk/total- -net/total- ---paging-- ---system--
usr sys idl wai hiq siq| read  writ| recv  send|  in   out | int   csw
 19  45  35   0   0   0|  30k  265k|   0     0 |   0     0 |9025    12k
  9  18  73   0   0   0|   0   144k|2578k   65k|   0     0 |3956  4343
  
6)可以使用iostat查看IO負載
[root@localhost ~]# iostat 1 1
Linux 2.6.32-696.16.1.el6.x86_64 (nc-ftp01.kevin.cn)    2017年12月29日     _x86_64_    (4 CPU)
  
avg-cpu:  %user   %nice %system %iowait  %steal   %idle
          19.32    0.00   45.44    0.06    0.26   34.93
  
Device:            tps   Blk_read/s   Blk_wrtn/s   Blk_read   Blk_wrtn
xvda             14.17        29.94       265.17   63120486  558975100
 
解釋說明:
avg-cpu: 總體cpu使用情況統計信息,對於多核cpu,這里為所有cpu的平均值
%user: 在用戶級別運行所使用的CPU的百分比.
%nice: nice操作所使用的CPU的百分比.
%sys: 在系統級別(kernel)運行所使用CPU的百分比.
%iowait: CPU等待硬件I/O時,所占用CPU百分比.
%idle: CPU空閑時間的百分比.
 
Device段:各磁盤設備的IO統計信息
tps: 每秒鍾發送到的I/O請求數.
Blk_read /s: 每秒讀取的block數.
Blk_wrtn/s: 每秒寫入的block數.
Blk_read:   讀入的block總數.
Blk_wrtn:  寫入的block總數.
 
[root@localhost ~]# iostat -x -k -d 1
Linux 2.6.32-696.el6.x86_64 (centos6-vm02)  01/04/2018  _x86_64_    (4 CPU)
 
Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
scd0              0.00     0.00    0.00    0.00     0.00     0.00     8.00     0.00    0.36    0.36    0.00   0.36   0.00
vda               0.01     0.13    0.04    0.13     0.60     0.89    18.12     0.00    2.78    0.19    3.53   2.55   0.04
dm-0              0.00     0.00    0.04    0.22     0.58     0.88    11.25     0.00    3.27    0.25    3.82   1.61   0.04
dm-1              0.00     0.00    0.00    0.00     0.00     0.00     8.00     0.00    0.13    0.13    0.00   0.04   0.00
dm-2              0.00     0.00    0.00    0.00     0.00     0.00     7.91     0.00    0.19    0.10    5.00   0.16   0.00
 
解釋說明:
rrqm/s: 每秒對該設備的讀請求被合並次數,文件系統會對讀取同塊(block)的請求進行合並
wrqm/s: 每秒對該設備的寫請求被合並次數
r/s: 每秒完成的讀次數
w/s: 每秒完成的寫次數
rkB/s: 每秒讀數據量(kB為單位)
wkB/s: 每秒寫數據量(kB為單位)
avgrq-sz:平均每次IO操作的數據量(扇區數為單位)
avgqu-sz: 平均等待處理的IO請求隊列長度
await: 平均每次IO請求等待時間(包括等待時間和處理時間,毫秒為單位)
svctm: 平均每次IO請求的處理時間(毫秒為單位)
%util: 采用周期內用於IO操作的時間比率,即IO隊列非空的時間比率
 
如果 %util 接近 100%,說明產生的I/O請求太多,I/O系統已經滿負荷,該磁盤可能存在瓶頸。
idle小於70% IO壓力就較大了,一般讀取速度有較多的wait。
同時可以結合vmstat 查看查看b參數(等待資源的進程數)和wa參數(IO等待所占用的CPU時間的百分比,高過30%時IO壓力高)

三、buffers和cached解釋

緩存(cached)是把讀取過的數據保存起來,重新讀取時若命中(找到需要的數據)就不要去讀硬盤了,若沒有命中就讀硬盤。其中的數據會根據讀取頻率進行組織,把最頻繁讀取的內容放在最容易找到的位置,把不再讀的內容不斷往后排,直至從中刪除。

緩沖(buffers)是根據磁盤的讀寫設計的,把分散的寫操作集中進行,減少磁盤碎片和硬盤的反復尋道,從而提高系統性能。linux有一個守護進程定期清空緩沖內容(即寫入磁盤),也可以通過sync命令手動清空緩沖。舉個例子吧:我這里有一個ext2的U盤,我往里面cp一個3M的MP3,但U盤的燈沒有跳動,過了一會兒(或者手動輸入sync)U盤的燈就跳動起來了。卸載設備時會清空緩沖,所以有些時候卸載一個設備時要等上幾秒鍾。

修改/etc/sysctl.conf中的vm.swappiness右邊的數字可以在下次開機時調節swap使用策略。該數字范圍是0~100,數字越大越傾向於使用swap。默認為60,可以改一下試試。–兩者都是RAM中的數據。

兩者都是RAM中的數據,簡單來說,buffer是即將要被寫入磁盤的,而cache是被從磁盤中讀出來的。
buffer是由各種進程分配的,被用在如輸入隊列等方面。一個簡單的例子如某個進程要求有多個字段讀入,在所有字段被讀入完整之前,進程把先前讀入的字段放在buffer中保存。
cache經常被用在磁盤的I/O請求上,如果有多個進程都要訪問某個文件,於是該文件便被做成cache以方便下次被訪問,這樣可提高系統性能。

Cache:緩沖區,高速緩存,是位於CPU與主內存間的一種容量較小但速度很高的存儲器。由於CPU的速度遠高於主內存,CPU直接從內存中存取數據要等待一定時間周期,Cache中保存着CPU剛用過或循環使用的一部分數據,當CPU再次使用該部分數據時可從Cache中直接調用,這樣就減少了CPU的等待時間,提高了系統的效率。Cache又分為一級Cache(L1 Cache)和二級Cache(L2 Cache),L1 Cache集成在CPU內部,L2 Cache早期一般是焊在主板上,現在也都集成在CPU內部,常見的容量有256KB或512KB L2 Cache。它是根據程序的局部性原理而設計的,就是cpu執行的指令和訪問的數據往往在集中的某一塊,所以把這塊內容放入cache后,cpu就不用在訪問內存了,這就提高了訪問速度。當然若cache中沒有cpu所需要的內容,還是要訪問內存的。從內存讀取與磁盤讀取角度考慮,cache可以理解為操作系統為了更高的讀取效率,更多的使用內存來緩存可能被再次訪問的數據。

Cache並不是緩存文件的,而是緩存塊的(塊是I/O讀寫最小的單元);Cache一般會用在I/O請求上,如果多個進程要訪問某個文件,可以把此文件讀入Cache中,這樣下一個進程獲取CPU控制權並訪問此文件直接從Cache讀取,提高系統性能。

Buffer:緩沖區,一個用於存儲速度不同步的設備或優先級不同的設備之間傳輸數據的區域通過buffer可以減少進程間通信需要等待的時間,當存儲速度快的設備與存儲速度慢的設備進行通信時,存儲慢的數據先把數據存放到buffer,達到一定程度存儲快的設備再讀取buffer的數據,在此期間存儲快的設備CPU可以干其他的事情。

Buffer:一般是用在寫入磁盤的,例如:某個進程要求多個字段被讀入,當所有要求的字段被讀入之前已經讀入的字段會先放到buffer中。Buffer是根據磁盤的讀寫設計的,把分散的寫操作集中進行,減少磁盤碎片和硬盤的反復尋道,從而提高系統性能。linux有一個守護進程定期清空緩沖內容(即寫入磁盤),也可以通過sync命令手動清空緩沖。

cache是高速緩存,用於CPU和內存之間的緩沖;
buffer是I/O緩存,用於內存和硬盤的緩沖;

cache最初用於cpu cache,主要原因是cpu 與memory,由於cpu快,memory跟不上,且有些值使用次數多,所以放入cache中,主要目的是,重復使用,並且一級\二級物理cache速度快,
buffer主要用於disk與 memory,主要是保護硬盤或減少網絡傳輸的次數(內存數據表現dataSet).當然也可以提高速度(不會立即寫入硬盤或直接從硬盤中讀出的數據馬上顯示),重復使用,最初最主要的目的是保護disk,

Free中的buffer和cache:(它們都是占用內存):
buffer : 作為buffer cache的內存,是塊設備的讀寫緩沖區
cache: 作為page cache的內存, 文件系統的cache

如果 cache 的值很大,說明cache住的文件數很多。如果頻繁訪問到的文件都能被cache住,那么磁盤的讀IO bi會非常小。

========================================================
下面通過一些簡單通俗的例子來說明下Cache和Buffer緩存之間的區別:

1)Cache緩存

假設某地發生了自然災害(比如地震),居民缺衣少食,於是派救火車去給若干個居民點送水。救火車到達第一個居民點,開閘放水,老百姓就拿着盆盆罐罐來接水。假如說救火車在一個居民點停留100分鍾放完了水,然后重新儲水花半個小時,再開往下一個居民點。這樣一個白天來來來回回的,也就是4-5個居民點。

但我們想想,救火車是何等存在,如果把水龍頭完全打開,其強大的水壓能輕易沖上10層樓以上, 10分鍾就可以把水全部放完。但因為居民是拿盆罐接水,100%打開水龍頭那就是給人洗澡了,所以只能打開一小部分(比如10%的流量)。但這樣就降低了放水的效率(只有原來的10%了),10分鍾變100分鍾。

那么,我們是否能改進這個放水的過程,讓救火車以最高效率放完水、盡快趕往下一個居民點呢?
方法就是:在居民點建蓄水池。
救火車把水放到蓄水池里,因為是以100%的效率放水,10分鍾結束然后走人。居民再從蓄水池里一點一點的接水。

我們分析一下這個例子,就可以知道Cache的含義了。
救火車要給居民送水,居民要從救火車接水,就是說居民和救火車之間有交互,有聯系。
但救火車是"高速設備",居民是"低速設備",低速的居民跟不上高速的救火車,所以救火車被迫降低了放水速度以適應居民。
為了避免這種情況,在救火車和居民之間多了一層"蓄水池(也就是Cache)",它一方面以100%的高效和救火車打交道,另一方面以10%的低效和居民打交道,這就解放了救火車,讓其以最高的效率運行,而不被低速的居民拖后腿,於是救火車只需要在一個居民點停留10分鍾就可以了。
所以說,蓄水池是"活雷鋒",把高效留給別人,把低效留給自己。把10分鍾留給救火車,把100分鍾留給自己。

從以上例子可以看出,所謂Cache,就是"為了彌補高速設備和低速設備之間的矛盾"而設立的一個中間層。因為在現實里經常出現高速設備要和低速設備打交道,結果被低速設備拖后腿的情況Cache的存在是為了解決什么問題?速度太慢了,要加快速度!

以PC為例。CPU速度很快,但CPU執行的指令是從內存取出的,計算的結果也要寫回內存,但內存的響應速度跟不上CPU。CPU跟內存說:你把某某地址的指令發給我。內存聽到了,但因為速度慢,遲遲不見指令返回,這段時間,CPU只能無所事事的等待了。這樣一來,再快的CPU也發揮不了效率。
怎么辦呢?在CPU和內存之間加一塊"蓄水池",也就是Cache(片上緩存),這個Cache速度比內存快,從Cache取指令不需要等待。當CPU要讀內存的指令的時候先讀Cache再讀內存,但一開始Cache是空着的,只能從內存取,這時候的確是很慢,CPU需要等待。但從內存取回的不僅僅是CPU所需要的指令,還有其它的、當前不需要的指令,然后把這些指令存在Cache里備用。CPU再取指令的時候還是先讀Cache,看看里面有沒有所需指令,如果碰巧有就直接從Cache取,不用等待即可返回(命中),這就解放了CPU,提高了效率。(當然不會是100%命中,因為Cache的容量比內存小)

2)Buffer緩存

比如說吐魯番的葡萄熟了,要用大卡車裝葡萄運出去賣果園的姑娘采摘葡萄,當然不是前手把葡萄摘下來,后手就放到卡車上,而是需要一個中間過程"籮筐":摘葡萄→放到籮筐里→把籮筐里的葡萄倒入卡車。也就是說,雖然最終目的是"把葡萄倒入卡車",但中間必須要經過"籮筐"的轉手,這里的籮筐就是Buffer。是"暫時存放物品的空間"。
注意2個關鍵詞:暫時,空間
再換句話說,為了完成最終目標:把葡萄放入卡車的空間,需要暫時把葡萄放入籮筐的空間。

以BT為例,BT下載需要長時間的掛機,電腦就有可能24小時連軸轉,但BT下載的數據是碎片化的,體現在硬盤寫入上也是碎片化的,因為硬盤是機械尋址器件,這種碎片化的寫入會造成硬盤長時間高負荷的機械運動,造成硬盤過早老化損壞,當年有大量的硬盤因為BT下載而損壞。於是新出的BT軟件在內存里開辟了Buffer,數據暫時寫入Buffer,攢到一定的大小(比如512M)再一次性寫入硬盤,這種"化零為整"的寫入方式大大降低了硬盤的負荷。這就是:為了完成最終目標:把數據寫入硬盤空間,需要暫時寫入Buffer的空間。

3)二者之間的區別總結

Cache和Buffer的相同點:都是2個層面之間的中間層,都是內存。
Cache和Buffer的不同點:Cache解決的是時間問題,Buffer解決的是空間問題。
為了提高速度,引入了Cache這個中間層。
為了給信息找到一個暫存空間,引入了Buffer這個中間層。
為了解決2個不同維度的問題(時間、空間),恰巧取了同一種解決方法:加入一個中間層,先把數據寫到中間層上,然后再寫入目標。
這個中間層就是內存“RAM”,既然是存儲器就有2個參數:寫入的速度有多塊(速度),能裝多少東西(容量)
Cache利用的是RAM提供的高讀寫速度,Buffer利用的是RAM提供的存儲容量(空間)。

簡言之:
1. Buffer(緩沖區)是系統兩端處理速度平衡(從長時間尺度上看)時使用的。它的引入是為了減小短期內突發I/O的影響,起到流量整形的作用。比如生產者——消費者問題,他們產生和消耗資源的速度大體接近,加一個buffer可以抵消掉資源剛產生/消耗時的突然變化。
2. Cache(緩存)則是系統兩端處理速度不匹配時的一種折衷策略。因為CPU和memory之間的速度差異越來越大,所以人們充分利用數據的局部性(locality)特征,通過使用存儲系統分級(memory hierarchy)的策略來減小這種差異帶來的影響。
3. 假定以后存儲器訪問變得跟CPU做計算一樣快,cache就可以消失,但是buffer依然存在。比如從網絡上下載東西,瞬時速率可能會有較大變化,但從長期來看卻是穩定的,這樣就能通過引入一個buffer使得OS接收數據的速率更穩定,進一步減少對磁盤的傷害。

四、手動清理緩存

釋放緩存區內存的方法
1)清理pagecache(頁面緩存)
[root@backup ~]# echo 1 > /proc/sys/vm/drop_caches     或者 # sysctl -w vm.drop_caches=1

2)清理dentries(目錄緩存)和inodes
[root@backup ~]# echo 2 > /proc/sys/vm/drop_caches     或者 # sysctl -w vm.drop_caches=2

3)清理pagecache、dentries和inodes
[root@backup ~]# echo 3 > /proc/sys/vm/drop_caches     或者 # sysctl -w vm.drop_caches=3
  
上面三種方式都是臨時釋放緩存的方法,要想永久釋放緩存,需要在/etc/sysctl.conf文件中配置:vm.drop_caches=1/2/3,然后sysctl -p生效即可!

另外,可以使用sync命令來清理文件系統緩存,還會清理僵屍(zombie)對象和它們占用的內存
[root@backup ~]# sync


溫馨提示:
上面操作在大多數情況下都不會對系統造成傷害,只會有助於釋放不用的內存。
但是如果在執行這些操作時正在寫數據,那么實際上在數據到達磁盤之前就將它從文件緩存中清除掉了,這可能會造成很不好的影響。

那么如果避免這種事情發生呢?
因此,這里不得不提一下/proc/sys/vm/vfs_cache_pressure這個文件,告訴內核,當清理inoe/dentry緩存時應該用什么樣的優先級。
[root@backup ~]# cat /proc/sys/vm/vfs_cache_pressure
100

vfs_cache_pressure=100    這個是默認值,內核會嘗試重新聲明dentries和inodes,並采用一種相對於頁面緩存和交換緩存比較"合理"的比例。

減少vfs_cache_pressure的值,會導致內核傾向於保留dentry和inode緩存。
增加vfs_cache_pressure的值,(即超過100時),則會導致內核傾向於重新聲明dentries和inodes
 
總之,vfs_cache_pressure的值:
小於100的值不會導致緩存的大量減少
超過100的值則會告訴內核你希望以高優先級來清理緩存。
 
其實無論vfs_cache_pressure的值采用什么值,內核清理緩存的速度都是比較低的。
如果將此值設置為10000,系統將會將緩存減少到一個合理的水平。
======================================================

這里順便說下自己遇到的一個內存問題:
IDC機房有一台專門的備份服務器,每天凌晨執行多個備份腳本。某天早上突然發現收到很多條zabbix監控報警信息:這台備份服務器的內存使用了已超過80%!
於是,趕緊登陸這台備份服務器,使用free命令查看內存使用情況:
[root@backup ~]# free -m
             total       used       free     shared    buffers     cached
Mem:         64181      48585      15596          3          2         18
-/+ buffers/cache:      48564      15617
Swap:        32767          0      3276

確實發現內存使用率已超過80%!但是使用"top"命令查看,發現此時並沒有什么進程在占用內存,並且本機是備份服務器,只有晚上執行備份腳本,
其他時間都沒有服務進程在跑!於是嘗試手動釋放內存:
[root@backup ~]# echo 1 > /proc/sys/vm/drop_caches
[root@backup ~]# echo 2 > /proc/sys/vm/drop_caches
[root@backup ~]# echo 3 > /proc/sys/vm/drop_caches
[root@backup ~]# sync

發現在執行了上面第三條命令后,內存才真正被釋放出來了,其他命令都沒有起到效果。

五、"Cannot allocate memory"問題

啟動服務器上的tomcat服務,發現啟動后服務沒有起來!查看日志發現"Cannot allocate memory",內存不夠了!

[root@tomcat ~]# /opt/tomcat_b/tomcat_7777/startup.sh start

[root@tomcat ~]# ps -ef|grep tomcat_7777
bxapp      2165   1821  0 11:50 pts/5    00:00:00 grep tomcat_7777
[root@tomcat ~]# 

[root@tomcat ~]# cat catalina.out
Java HotSpot(TM) 64-Bit Server VM warning: INFO: os::commit_memory(0x00000000a0000000, 1610612736, 0) failed; error='Cannot allocate memory' (errno=12)
#
# There is insufficient memory for the Java Runtime Environment to continue.
# Native memory allocation (mmap) failed to map 1610612736 bytes for committing reserved memory.
# An error report file with more information is saved as:
# /opt/tomcat_b/pay-service/hs_err_pid125225.log
Java HotSpot(TM) 64-Bit Server VM warning: INFO: os::commit_memory(0x00000000a0000000, 1610612736, 0) failed; error='Cannot allocate memory' (errno=12)
#
# There is insufficient memory for the Java Runtime Environment to continue.
# Native memory allocation (mmap) failed to map 1610612736 bytes for committing reserved memory.
# An error report file with more information is saved as:
# /opt/tomcat_b/tomcat_7777/bin/hs_err_pid125352.log

解決"Cannot allocate memory"問題的方法(內存不夠,沒法分配內存):
1)調整系統的內存參數
# echo 1 > /proc/sys/vm/overcommit_memory   # 臨時修改
# vim /etc/sysctl.conf                      # 永久修改
vm.overcommit_memory=1
# sysctl -p

2) 調整系統的最大進程數目
查看系統允許的當前最大進程數
主要是查看pid_max指標的,pid_max是Linux內核用來限制進程數的一個最大指標。
換言之,即最大允許進程就這么多,超過了這個設定值,服務器就掛了("ps -eLf | wc -l"查看本機器的進程數)
# sysctl kernel.pid_max    # centos7系統執行"systemctl kernel.pid_max"命令
kernel.pid_max = 32768
或者
# cat /proc/sys/kernel/pid_max
32768

一般出現 -bash: fork: Cannot allocate memory 本機的進程數應該接近或等於pid_max指標值的。
# echo 65536 > /proc/sys/kernel/pid_max                   # 臨時修改
# echo "kernel.pid_max=65536" >> /etc/sysctl.conf         # 永久修改
# sysctl -p 
kernel.pid_max = 65536

3)調整項目部署的tomcat的jvm內存參數
在setenv.sh或catalina.sh文件里重新調整內存,這種情況是設置的過大,包括-Xms2048M、-Xmx2048M、-Xmn512M、-Xss1024K、NewSize=256M、-XX:MaxNewSize=512M 這樣的值,
物理內存不夠,把配置調小即可。

4)設置swap或者調大swap內存太小。有時系統默認沒有開啟虛擬內存,就會經常遇到軟件內存不足,運行崩潰的情況。
有時在雲服務器上(比如阿里雲),為了減少購買昂貴的內存資源,可以暫時使用虛擬內存代替(根據運行的程序需求,性能會降低一些)。
swap虛擬內存說明和運維注意點:
https://www.cnblogs.com/kevingrace/p/5991604.html
https://www.cnblogs.com/kevingrace/p/5570197.html

1. 查看內存使用情況,發現swap虛擬內存空間竟然為0
# free -m  
2. 建虛擬內存磁盤卷。做法如下:
# dd if=/dev/zero of=/opt/swap bs=1024 count=2048000
# mkswap /opt/swap
# swapon /opt/swap

再次查看內容,發現swap虛擬內存就有了
# free -m

3. 如果想取消文件虛擬內存,即刪除swap,做法如下:(當然根據系統配置,也可以保留swap,以后繼續用)。
# swapoff /opt/swap
# rm /opt/swap

4. swap開機掛載
# vim /etc/fstab
/opt/swap  swap                    swap    defaults        0 0

上面掛載參數分別為:
設備文件或偽文件系統   掛載點  文件系統類型  掛載選項 備份頻率 開機自檢次序

===========================================================================
這里順便說下,阿里雲服務器默認沒有開啟虛擬內存,經常遇到軟件內存不足,運行崩潰的情況。
阿里雲虛擬機上創建swap虛擬內存磁盤卷的做法如下:

大概count=2024288,2G左右,可以視磁盤大小和需求創建。

1. 默認存放在/swap/swapadd,可以是自己的任何目錄。
阿里雲服務器默認沒有swap,需要自己創建。
# mkdir /swap
# dd if=/dev/zero of=/swap/swapadd bs=1024 count=2024288

2. 將磁盤卷轉為虛擬內存卷
# mkswap /swap/swapadd

3. 啟用虛擬內存服務
# swapon /swap/swapadd

4. 這時再查看內存,發現已經開啟了swap虛擬內存。即多出來2G左右的swap空間。
# free -m

5. 如果想再關閉虛擬內存服務,執行下面命令即可:
# swapoff -v /swap/swapadd

6. 移動虛擬內存空間
如果當前的虛存所在的磁盤空間不夠,可以首先關閉虛存服務,將其移動到別的磁盤,再啟用即可。
# swapoff -v /swap/swapadd
# mv /swap/swapadd /mnt/swap
# swapon /swap/swapadd

5)極端情況:沒有足夠內存分配,導致機器操作一直處於卡着的情況!
在linux終端里執行命令時,發現"-bash: fork: Cannot allocate memory:"問題即進程數滿了!!
出現這種情況,主要是因為進程跑滿了,memory被消耗光了,無法再為其他操作分配內存,包括執行一般操作命令和SSH連接分配內存!
除了上面四種處理方式外,還有一種比較粗暴的的方法,就是重啟服務器,注意不是重啟tomcat!
# init 6   
如果執行"init 6"重啟機器不行,就使用"reboot"或者"init 0"強制重啟(可能需要多敲幾次)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM