前段時間業(yè)務反映某類服務器上更新了 bash 之后,ssh 連上去偶發(fā)登陸失敗,客戶端吐出錯誤信息如下所示:
iOS培訓,Swift培訓,蘋果開發(fā)培訓,移動開發(fā)培訓
圖 - 0

該版本 bash 為部門這邊所定制,但實現上并沒有改動原有邏輯,只是加入了些監(jiān)控功能,那么這些錯誤從哪里來呢?

是 bash 的鍋嗎

從上面的錯誤信息可以猜測,異常是 bash 在啟動過程中分配內存失敗所導致,看起來像是某些情況下該進程錯誤地進行了大量內存分配,最后導致內存不足,要確認這個事情比較簡單,動態(tài)內存分配到系統(tǒng)調用這一層上主要就兩種方式: brk() 和 mmap(), 所以只要統(tǒng)計一下這兩者的調用就可以大概估算出是否有大內存分配了。

bash 是由 sshd 啟動的,于是 strace 跟蹤了一下 sshd 進程,結果發(fā)現異常發(fā)生時,bash 分配的內存非常地少,少到有時甚至只有幾十字節(jié)也會失敗,幾乎可以斷定 bash 在內存使用上沒有異常,但在這期間發(fā)現一個詭異的現象,Bash 一直只用 brk 在分配小內存,brk() 失敗后就直接退出了,一般程序使用的 libc 中的 malloc (或其它類似的 malloc) 會結合 brk 和 mmap 一起使用【0】,不至于 brk 一失敗就分配不到內存,順手查看了下 bash 的源碼,發(fā)現它確實只基于 brk 做了自己的內存管理,并沒有使用 malloc 或 mmap。

但那并不是重點,重點是即使是只使用 brk,也不至于只能分配幾十字節(jié)的內存。

進程的內存布局

進程的內存布局在結構上是有規(guī)律的,具體來說對于 linux 系統(tǒng)上的進程,其內存空間一般可以粗略地分為以下幾大段【1】,從高內存到低內存排列:
1、內核態(tài)內存空間,其大小一般比較固定(可以編譯時調整