成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Linux 內存變低會發生什么問題

系統 Linux
內存不是無限的,總有不夠用的時候,Linux內核用三個機制來處理這種情況:內存回收、內存規整、oom-kill。

作者 | cynrikluo

內存不是無限的,總有不夠用的時候,linux內核用三個機制來處理這種情況:內存回收、內存規整、oom-kill。

當發現內存不足時,內核會先嘗試內存回收,從一些進程手里拿回一些頁;如果這樣還是不能滿足申請需求,則觸發內存規整;再不行,則觸發oom主動kill掉一個不太重要的進程,釋放內存。

低內存情況下,內核的處理邏輯

內存申請的核心函數是__alloc_pages_nodemask:

/*
 * This is the 'heart' of the zoned buddy allocator.
 */
struct page *
__alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order, int preferred_nid,
              nodemask_t *nodemask)
{
  struct page *page;
  unsigned int alloc_flags = ALLOC_WMARK_LOW;
  gfp_t alloc_mask; /* The gfp_t that was actually used for allocation */
  struct alloc_context ac = { }; 

__alloc_pages_nodemask會先嘗試調用get_page_from_freelist從伙伴系統的freelist里拿空閑頁,如果能拿到就直接返回:

如果拿不到,則進入慢速路徑:

__alloc_pages_slowpath,慢速路徑,顧名思義,就是拿得慢一點,需要做一些操作以后再拿。

首先, __alloc_pages_slowpath會喚醒kswapd:

kswapd是一個守護進程,專門進行內存回收操作,執行路徑:

它被喚醒后,會立1刻開始進行回收,效率高的話,freelist上會立刻多出很多空閑頁。

所以 __alloc_pages_slowpath會馬上再次嘗試從freelist獲取頁面,獲取成功則直接返回了。

若還是失敗, __alloc_pages_slowpath則會進入direct_reclaim階段:

direct_reclaim,顧名思義,就是直接內存回收,回收到的頁不用放回freelist再get_page_from_freelist這么麻煩了,也不用喚醒某個進程幫忙回收,而是由當前進程(current)親自下場去回收,執行路徑:

如果direct_reclaim也回收不上來, __alloc_pages_slowpath還會垂死掙扎下,做一下內存規整,嘗試把零散的頁輾轉騰挪,拼成為大order頁(僅在申請order>0的頁時有用)。

如果還是無法滿足要求,則進入oom-kill了:

總結上面的邏輯:內存申請時,首先嘗試直接從freelist里拿;失敗了則先喚醒kswapd幫忙回收內存;若內存低到讓kswapd也愛莫能助,則進入direct reclaim直接回收內存;若direct reclaim也無能為力,則oom:

三條水線

實際上,從freelist上拿頁不是簡單地直接拿,而是先檢查下該zone是否滿足水線要求,不滿足那就直接失敗。

內核給內存管理劃了三條水線:MIN、LOW、HIGH。

三者大小關系從字面即可推斷,MIN < LOW < HIGH。

在首次嘗試從freelist拿頁時,門檻水線是LOW;喚醒kswapd后再次嘗試拿頁,門檻水線是MIN。

所以實際邏輯如下:

所以,可以簡單地認為,可用內存低于LOW水線時,喚醒kswapd;低于MIN水線時,進行direct reclaim;而HIGH水線,是kswapd的回收終止線:

為什么內存回收時,磁盤IO會被打滿?

可以看到,kswapd和direct_reclaim最終都是走到了shrink_node:

shrink_node是內存回收的核心函數,顧名思義,讓整個node進行一次“收縮”,把不要的數據清掉,空出空閑頁。

get_scan_count決定本次掃描多少個anon page和file page。

anon page就是Anonymous Page,匿名頁,是進程的堆棧、數據段等。內核回收匿名頁時,將這些數據進行壓縮(壓縮比大概為3),然后移動到內存中的一個小角落中(swap空間),這個過程并沒有與磁盤發生交互,因此不會產生IO,但需要壓縮數據,所以耗CPU。

file page就是文件頁,是進程的代碼段、映射的文件。內核回收文件頁時,先將“臟”數據回寫到磁盤,然后釋放掉這些緩存數據,干凈的數據則直接釋放掉。這個過程涉及到寫磁盤,因此會產生IO。

簡單總結一下get_scan_count的邏輯:

所以說,不論開沒開swap,內存回收都是傾向于回收file page。

如果file page中有臟頁,那內存回收大概率就會產生一些IO,無非是IO量多少罷了。

以下情況IO可能會打滿或者暴增:

  • 當前內存不是特別緊張,但low、min水線設置得太低,之前一直沒怎么觸發過內存回收,以致于臟頁已經累積到大量,一觸發回收,立刻就是回寫大量臟頁,導致IO暴增。
  • 內存極度緊張 (free 和available同時很低)。這種情況下,anon page遠比file page多,這意味著可回收的內存很少,內核會對活躍數據下手,一些進程上一秒還用著的數據,這一秒可能就被不幸回收了,但下一秒馬上又要被使用,會再次被讀入內存。如此,同一份數據,內核就進行了多次回收和讀入,IO就加倍了。

為什么低內存有時會引發hungtask?

低內存時,通常不是個別進程觸發了direct reclaim,而是大量進程都在direct reclaim。

大家都要回寫臟頁,于是IO被打滿了。

這時候,進程會頻繁地被IO阻塞,被阻塞的進程為了不占用CPU,會調用io_schedule_timeout或io_schedule來掛起自己,直到IO完成。

這種等待是D狀態的,一旦超過了120S,就會觸發hungtask。當然,這是非常極端的情況,IO已經完全沒救的情況。

大部分時候,IO雖然打滿了,但是總能周轉過來,所以這些進程并不會等太久。

然而,這些進程若是來自同一個業務,則大概率會訪問同一個數據,這就需要通過mutex、rwsem、semaphore等同步機制來控制訪問行為。

而這些同步機制的基本接口都是uninterruptible性質的,以semaphore為例:

extern void down(struct semaphore *sem); // 基本接口。獲取信號量,獲取不到則進入uninterruptible睡眠
extern int __must_check down_interruptible(struct semaphore *sem); // 其他接口
extern int __must_check down_killable(struct semaphore *sem); // 其他接口
extern int __must_check down_trylock(struct semaphore *sem); // 其他接口
extern int __must_check down_timeout(struct semaphore *sem, long jiffies); // 其他接口

所謂uninterruptible性質,即當進程獲取不到同步資源時,直接進入D狀態等待其他進程釋放資源。

其他同步資源,rwsem、mutex等,都有這樣的uninterruptible性質接口。

正常情況下,只要持有同步資源的進程正常運行不卡頓,那么即使有上百個進程來爭搶這些同步資源,對于排序靠后的進程來說,時間也是夠的,一般不會等待超過120s。

但在低內存情況下,大家都在等IO,這些持有資源的進程也不能幸免,引發堵車連鎖反應。

如果此時同步資源的waiter們已累計了幾十個甚至上百個,那么就算只有一瞬間的io卡頓,排序靠后的waiter也容易等待超過120s,觸發hungtask。

一個非常典型的案例,一臺CVM在連續報了幾條hungtask warning后,徹底無響應了,通過魔術建觸發重啟。

系統信息如下:

內存狀況不容樂觀,典型的低內存:

log上有很多hungtask warning,超時原因都是等rwsem太長,寫者waiter和讀者waiter都有:

這些進程在等同一個rwsem,這個rwsem的地址為:ffff880e9703f370

進一步探究,發現當前對ffff880e9703f370有引用的進程為19個,11個正在讀,8個排隊。

而這11個正在讀的進程,都在做同一件事——direct reclaim,并且都卡在IO等待:

這11個進程,雖然也是D狀態,但由于時不時能調度到IO,相當于D狀態的持續時間不斷重置,所以本身并沒有觸發hungtask。

而這8個waiter進程就沒這個好運了,被前面11個進程你方唱罷我登場地阻塞,持續時間也沒有機會重置,最終超過120s,引發hungtask了。

優化低內存處理

我們已經知道了低內存會導致IO突增,甚至導致hungtask,那要如何避免呢?

可以從兩方面來避免。

(1) 調整臟頁回刷頻率

將平時的臟頁回刷頻率調高,這樣內存回收時,需要回收的臟頁就更少,降低IO的增量。

  • 調低 /proc/sys/vm/dirty_writeback_centisecs
  • 調低/proc/sys/vm/dirty_background_ratio
(2) 調高low水線和min水線

調高水線,可以更早地進入內存回收邏輯,這樣可以將free維持在一個較高水平,避免陷入極端場景。由于low和min同時受min_free_kbytes管控,所以可以直接調整min_free_kbytes值。

調高/proc/sys/vm/min_free_kbytes

責任編輯:趙寧寧 來源: 騰訊技術工程
相關推薦

2023-08-26 07:44:13

系統內存虛擬

2021-03-10 10:40:04

Redis命令Linux

2020-12-10 07:37:42

HashMap數據覆蓋

2021-08-19 17:27:41

IT數據中心災難

2021-12-27 08:24:08

漏洞網絡安全

2015-09-25 10:41:48

r語言

2023-06-27 16:53:50

2015-11-19 00:11:12

2016-01-04 11:03:00

2015-04-16 10:40:29

2024-01-18 11:50:28

2023-04-27 07:40:08

Spring框架OpenAI

2019-02-27 10:18:26

重置Windows 10Windows

2011-10-11 15:42:54

大數據數據庫

2012-12-25 15:19:20

Windows操作系統

2019-03-14 11:00:40

GoLua語言

2020-12-16 19:26:42

IIOTIOT工業物聯網

2020-06-15 08:06:25

ES數據

2018-06-06 00:26:20

SDN5G無線網絡

2023-05-04 00:16:39

數字化轉型運營
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国精产品一品二品国精在线观看 | 亚洲视频在线观看 | 九九免费视频 | 久久久久久久久蜜桃 | 日韩毛片免费看 | 精品伊人久久 | 国产有码| 日批免费观看 | 国产专区免费 | 99在线免费视频 | 黄色亚洲 | 日韩视频一区在线观看 | 99亚洲| 中文字字幕一区二区三区四区五区 | 国产亚洲精品综合一区 | 欧美亚洲视频 | 一区日韩 | 日韩精品视频在线播放 | 黄色在线播放视频 | 久久久久久黄 | 成人在线精品视频 | 亚洲精品1区 | 一区二区欧美在线 | 日本黄视频在线观看 | 国产精品99久久久久久www | 日韩中字幕 | 国产精品永久免费 | 国产一区三区视频 | 九九热精品视频 | 欧美日韩成人在线观看 | 精品国产91乱码一区二区三区 | 国产成人久久精品一区二区三区 | 久久久成人精品 | 第一色在线 | 国产精品成人在线 | 一区二区在线免费观看视频 | 久久久久久999| 青青青伊人 | 中文字幕专区 | 可以免费观看的av片 | 亚洲网在线 |