Linux性能優(yōu)化筆記3

notes

  • 32位每窖,3G用戶空間帮掉,1G核心空間。
  • 64位窒典,內(nèi)核和用戶均為128T蟆炊,剩下的未定義。用戶低位瀑志,核心高位涩搓。
  • 內(nèi)存分布污秆。
    只讀段,包括代碼和常量等昧甘。
    數(shù)據(jù)段良拼,包括全局變量等。
    堆疾层,包括動(dòng)態(tài)分配的內(nèi)存将饺,從低地址開始向上增長(zhǎng)。
    文件映射段痛黎,包括動(dòng)態(tài)庫予弧、共享內(nèi)存等,從高地址開始向下增長(zhǎng)湖饱。
    棧掖蛤,包括局部變量和函數(shù)調(diào)用的上下文等。棧的大小是固定的井厌,一般是 8 MB蚓庭。
  • 內(nèi)存分配涉及兩種系統(tǒng)調(diào)用:
    對(duì)小塊內(nèi)存(小于 128K),C 標(biāo)準(zhǔn)庫使用 brk() 來分配仅仆,也就是通過移動(dòng)堆頂?shù)奈恢脕矸峙鋬?nèi)存器赞。這些內(nèi)存釋放后并不會(huì)立刻歸還系統(tǒng),而是被緩存起來墓拜,這樣就可以重復(fù)使用港柜。
    而大塊內(nèi)存(大于 128K),則直接使用內(nèi)存映射 mmap() 來分配咳榜,也就是在文件映射段找一塊空閑內(nèi)存分配出去夏醉。
  • 回收不常訪問的內(nèi)存時(shí),會(huì)用到交換分區(qū)(以下簡(jiǎn)稱 Swap)涌韩。Swap 其實(shí)就是把一塊磁盤空間當(dāng)成內(nèi)存來用畔柔。它可以把進(jìn)程暫時(shí)不用的數(shù)據(jù)存儲(chǔ)到磁盤中(這個(gè)過程稱為換出),當(dāng)進(jìn)程訪問這些內(nèi)存時(shí)臣樱,再從磁盤讀取這些數(shù)據(jù)到內(nèi)存中(這個(gè)過程稱為換入)
  • oom,管理員可以通過 /proc 文件系統(tǒng)靶擦,手動(dòng)設(shè)置進(jìn)程的 oom_adj ,從而調(diào)整進(jìn)程的 oom_score雇毫。oom_adj 的范圍是 [-17, 15]奢啥,數(shù)值越大,表示進(jìn)程越容易被 OOM 殺死嘴拢;數(shù)值越小,表示進(jìn)程越不容易被 OOM 殺死寂纪,其中 -17 表示禁止 OOM席吴。
    【思考】有的時(shí)候發(fā)生oom赌结,是不是也要思考一下是不是可以調(diào)整oom_adj,因?yàn)閮?yōu)化進(jìn)程的效率比較低孝冒。
  • 緩存分buffer和cache
  • Buffers 是內(nèi)核緩沖區(qū)用到的內(nèi)存柬姚,對(duì)應(yīng)的是 /proc/meminfo 中的 Buffers 值。
    Buffers 是對(duì)原始磁盤塊的臨時(shí)存儲(chǔ)庄涡,也就是用來緩存磁盤的數(shù)據(jù)量承,通常不會(huì)特別大(20MB 左右)。這樣穴店,內(nèi)核就可以把分散的寫集中起來撕捍,統(tǒng)一優(yōu)化磁盤的寫入,比如可以把多次小的寫合并成單次大的寫等等泣洞。
  • Cache 是內(nèi)核頁緩存和 Slab 用到的內(nèi)存忧风,對(duì)應(yīng)的是 /proc/meminfo 中的 Cached 與 SReclaimable 之和。
    Cached 是從磁盤讀取文件的頁緩存球凰,也就是用來緩存從文件讀取的數(shù)據(jù)狮腿。這樣,下次訪問這些文件數(shù)據(jù)時(shí)呕诉,就可以直接從內(nèi)存中快速獲取缘厢,而不需要再次訪問緩慢的磁盤。
    SReclaimable 是 Slab 的一部分甩挫。Slab 包括兩部分贴硫,其中的可回收部分,用 SReclaimable 記錄捶闸;而不可回收部分夜畴,用 SUnreclaim 記錄。
    其實(shí):Buffer 是對(duì)磁盤數(shù)據(jù)的緩存删壮,而 Cache 是文件數(shù)據(jù)的緩存贪绘,它們既會(huì)用在讀請(qǐng)求中,也會(huì)用在寫請(qǐng)求中央碟。
  • Linux 提供了一個(gè) /proc/sys/vm/swappiness 選項(xiàng)税灌,用來調(diào)整使用 Swap 的積極程度。swappiness 的范圍是 0-100亿虽,數(shù)值越大菱涤,越積極使用 Swap,也就是更傾向于回收匿名頁洛勉;數(shù)值越小粘秆,越消極使用 Swap,也就是更傾向于回收文件頁收毫。
    可以設(shè)置 /proc/sys/vm/min_free_kbytes攻走,來調(diào)整系統(tǒng)定期回收內(nèi)存的閾值(也就是頁低閾值)殷勘,還可以設(shè)置 /proc/sys/vm/swappiness,來調(diào)整文件頁和匿名頁的回收傾向昔搂。

tools

free

# 注意不同版本的free輸出可能會(huì)有所不同
$ free
              total        used        free      shared  buff/cache   available
Mem:        8169348      263524     6875352         668     1030472     7611064
Swap:             0           0           0

第一列玲销,total 是總內(nèi)存大小摘符;
第二列贤斜,used 是已使用內(nèi)存的大小,包含了共享內(nèi)存逛裤;
第三列瘩绒,free 是未使用內(nèi)存的大小别凹;
第四列草讶,shared 是共享內(nèi)存的大小炉菲;
第五列堕战,buff/cache 是緩存和緩沖區(qū)的大小拍霜;
最后一列嘱丢,available 是新進(jìn)程可用內(nèi)存的大小。

top

# 按下M切換到內(nèi)存排序
$ top
...
KiB Mem :  8169348 total,  6871440 free,   267096 used,  1030812 buff/cache
KiB Swap:        0 total,        0 free,        0 used.  7607492 avail Mem


  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
  430 root      19  -1  122360  35588  23748 S   0.0  0.4   0:32.17 systemd-journal
 1075 root      20   0  771860  22744  11368 S   0.0  0.3   0:38.89 snapd
 1048 root      20   0  170904  17292   9488 S   0.0  0.2   0:00.24 networkd-dispat
    1 root      20   0   78020   9156   6644 S   0.0  0.1   0:22.92 systemd
12376 azure     20   0   76632   7456   6420 S   0.0  0.1   0:00.01 systemd
12374 root      20   0  107984   7312   6304 S   0.0  0.1   0:00.00 sshd
...

VIRT 是進(jìn)程虛擬內(nèi)存的大小祠饺,只要是進(jìn)程申請(qǐng)過的內(nèi)存越驻,即便還沒有真正分配物理內(nèi)存,也會(huì)計(jì)算在內(nèi)道偷。
RES 是常駐內(nèi)存的大小缀旁,也就是進(jìn)程實(shí)際使用的物理內(nèi)存大小,但不包括 Swap 和共享內(nèi)存勺鸦。
SHR 是共享內(nèi)存的大小并巍,比如與其他進(jìn)程共同使用的共享內(nèi)存、加載的動(dòng)態(tài)鏈接庫以及程序的代碼段等换途。
%MEM 是進(jìn)程使用物理內(nèi)存占系統(tǒng)總內(nèi)存的百分比懊渡。
tips:
第一,虛擬內(nèi)存通常并不會(huì)全部分配物理內(nèi)存军拟。從上面的輸出剃执,你可以發(fā)現(xiàn)每個(gè)進(jìn)程的虛擬內(nèi)存都比常駐內(nèi)存大得多。
第二懈息,共享內(nèi)存 SHR 并不一定是共享的肾档,比方說,程序的代碼段辫继、非共享的動(dòng)態(tài)鏈接庫阁最,也都算在 SHR 里戒祠。當(dāng)然,SHR 也包括了進(jìn)程間真正共享的內(nèi)存速种。所以在計(jì)算多個(gè)進(jìn)程的內(nèi)存使用時(shí),不要把所有進(jìn)程的 SHR 直接相加得出結(jié)果低千。

cachestat 提供了整個(gè)系統(tǒng)緩存的讀寫命中情況配阵。

$ cachestat 1 3
   TOTAL   MISSES     HITS  DIRTIES   BUFFERS_MB  CACHED_MB
       2        0        2        1           17        279
       2        0        2        1           17        279
       2        0        2        1           17        279 

TOTAL ,表示總的 I/O 次數(shù)示血;
MISSES 棋傍,表示緩存未命中的次數(shù);
HITS 难审,表示緩存命中的次數(shù)瘫拣;
DIRTIES, 表示新增到緩存中的臟頁數(shù)告喊;
BUFFERS_MB 表示 Buffers 的大小麸拄,以 MB 為單位;
CACHED_MB 表示 Cache 的大小黔姜,以 MB 為單位拢切。

cachetop 提供了每個(gè)進(jìn)程的緩存命中情況。

$ cachetop
11:58:50 Buffers MB: 258 / Cached MB: 347 / Sort: HITS / Order: ascending
PID      UID      CMD              HITS     MISSES   DIRTIES  READ_HIT%  WRITE_HIT%
   13029 root     python                  1        0        0     100.0%       0.0%

它的輸出跟 top 類似秆吵,默認(rèn)按照緩存的命中次數(shù)(HITS)排序淮椰,展示了每個(gè)進(jìn)程的緩存命中情況。具體到每一個(gè)指標(biāo)纳寂,這里的 HITS主穗、MISSES 和 DIRTIES ,跟 cachestat 里的含義一樣毙芜,分別代表間隔時(shí)間內(nèi)的緩存命中次數(shù)忽媒、未命中次數(shù)以及新增到緩存中的臟頁數(shù)。
而 READ_HIT 和 WRITE_HIT 爷肝,分別表示讀和寫的緩存命中率猾浦。

pcstat (指定文件在內(nèi)存中的緩存大小)

$ pcstat /bin/ls
+---------+----------------+------------+-----------+---------+
| Name    | Size (bytes)   | Pages      | Cached    | Percent |
|---------+----------------+------------+-----------+---------|
| /bin/ls | 133792         | 33         | 0         | 000.000 |
+---------+----------------+------------+-----------+---------+

memleak

# -a 表示顯示每個(gè)內(nèi)存分配請(qǐng)求的大小以及地址
# -p 指定案例應(yīng)用的PID號(hào)
$ /usr/share/bcc/tools/memleak -a -p $(pidof app)
WARNING: Couldn't find .text section in /app
WARNING: BCC can't handle sym look ups for /app
    addr = 7f8f704732b0 size = 8192
    addr = 7f8f704772d0 size = 8192
    addr = 7f8f704712a0 size = 8192
    addr = 7f8f704752c0 size = 8192
    32768 bytes in 4 allocations from stack
        [unknown] [app]
        [unknown] [app]
        start_thread+0xdb [libpthread-2.27.so] 

這里有一個(gè)問題,Couldn’t find .text section in /app灯抛,所以調(diào)用棧不能正常輸出金赦,最后的調(diào)用棧部分只能看到 [unknown] 的標(biāo)志。為什么會(huì)有這個(gè)錯(cuò)誤呢对嚼?實(shí)際上夹抗,這是由于案例應(yīng)用運(yùn)行在容器中導(dǎo)致的。

$ docker cp app:/app /app
$ /usr/share/bcc/tools/memleak -p $(pidof app) -a
Attaching to pid 12512, Ctrl+C to quit.
[03:00:41] Top 10 stacks with outstanding allocations:
    addr = 7f8f70863220 size = 8192
    addr = 7f8f70861210 size = 8192
    addr = 7f8f7085b1e0 size = 8192
    addr = 7f8f7085f200 size = 8192
    addr = 7f8f7085d1f0 size = 8192
    40960 bytes in 5 allocations from stack
        fibonacci+0x1f [app]
        child+0x4f [app]
        start_thread+0xdb [libpthread-2.27.so] 

utility

  • 使用top和ps查詢系統(tǒng)中大量占用內(nèi)存的進(jìn)程纵竖,使用cat /proc/[pid]/status和pmap -x pid查看某個(gè)進(jìn)程使用內(nèi)存的情況和動(dòng)態(tài)變化
  • 發(fā)生oom,查看哪個(gè)進(jìn)程被kill
    dmesg |grep -E ‘kill|oom|out of memory’
  • 查看各個(gè)進(jìn)程的實(shí)際物理內(nèi)存使用
    從 /proc/< pid >/smaps 入手
    動(dòng)手查 proc 文件系統(tǒng)的文檔
  • dd命令也支持直接IO的 有選項(xiàng)oflag和iflag 所以dd也可以用來繞過cache buff做測(cè)試
  • 最好禁止 Swap漠烧。如果必須開啟 Swap杏愤,降低 swappiness 的值,減少內(nèi)存回收時(shí) Swap 的使用傾向已脓。
  • 減少內(nèi)存的動(dòng)態(tài)分配珊楼。比如,可以使用內(nèi)存池度液、大頁(HugePage)等厕宗。
  • 盡量使用緩存和緩沖區(qū)來訪問數(shù)據(jù)。比如堕担,可以使用堆棧明確聲明內(nèi)存空間已慢,來存儲(chǔ)需要緩存的數(shù)據(jù);或者用 Redis 這類的外部緩存組件霹购,優(yōu)化數(shù)據(jù)的訪問佑惠。
  • 使用 cgroups 等方式限制進(jìn)程的內(nèi)存使用情況。這樣齐疙,可以確保系統(tǒng)內(nèi)存不會(huì)被異常進(jìn)程耗盡膜楷。
  • 通過 /proc/pid/oom_adj ,調(diào)整核心應(yīng)用的 oom_score剂碴。這樣把将,可以保證即使內(nèi)存緊張,核心應(yīng)用也不會(huì)被 OOM 殺死忆矛。

KKK快速定位性能問題

具體的分析思路主要有這幾步察蹲。
先用 free 和 top,查看系統(tǒng)整體的內(nèi)存使用情況催训。
再用 vmstat 和 pidstat洽议,查看一段時(shí)間的趨勢(shì),從而判斷出內(nèi)存問題的類型漫拭。
最后進(jìn)行詳細(xì)分析亚兄,比如內(nèi)存分配分析、緩存 / 緩沖區(qū)分析采驻、具體進(jìn)程的內(nèi)存使用分析等审胚。


image.png

第一個(gè)例子,當(dāng)你通過 free礼旅,發(fā)現(xiàn)大部分內(nèi)存都被緩存占用后膳叨,可以使用 vmstat 或者 sar 觀察一下緩存的變化趨勢(shì),確認(rèn)緩存的使用是否還在繼續(xù)增大痘系。
如果繼續(xù)增大菲嘴,則說明導(dǎo)致緩存升高的進(jìn)程還在運(yùn)行,那你就能用緩存 / 緩沖區(qū)分析工具(比如 cachetop、slabtop 等)龄坪,分析這些緩存到底被哪里占用昭雌。
第二個(gè)例子,當(dāng)你 free 一下健田,發(fā)現(xiàn)系統(tǒng)可用內(nèi)存不足時(shí)烛卧,首先要確認(rèn)內(nèi)存是否被緩存 / 緩沖區(qū)占用。排除緩存 / 緩沖區(qū)后妓局,你可以繼續(xù)用 pidstat 或者 top唱星,定位占用內(nèi)存最多的進(jìn)程。
找出進(jìn)程后跟磨,再通過進(jìn)程內(nèi)存空間工具(比如 pmap),分析進(jìn)程地址空間中內(nèi)存的使用情況就可以了攒盈。
第三個(gè)例子抵拘,當(dāng)你通過 vmstat 或者 sar 發(fā)現(xiàn)內(nèi)存在不斷增長(zhǎng)后,可以分析中是否存在內(nèi)存泄漏的問題型豁。
比如你可以使用內(nèi)存分配分析工具 memleak 僵蛛,檢查是否存在內(nèi)存泄漏。如果存在內(nèi)存泄漏問題迎变,memleak 會(huì)為你輸出內(nèi)存泄漏的進(jìn)程以及調(diào)用堆棧充尉。

思維導(dǎo)圖

image.png
image.png
image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市衣形,隨后出現(xiàn)的幾起案子驼侠,更是在濱河造成了極大的恐慌,老刑警劉巖谆吴,帶你破解...
    沈念sama閱讀 218,451評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件倒源,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡句狼,警方通過查閱死者的電腦和手機(jī)笋熬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來腻菇,“玉大人胳螟,你說我怎么就攤上這事〕锿拢” “怎么了糖耸?”我有些...
    開封第一講書人閱讀 164,782評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)骏令。 經(jīng)常有香客問我蔬捷,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,709評(píng)論 1 294
  • 正文 為了忘掉前任周拐,我火速辦了婚禮铡俐,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘妥粟。我一直安慰自己审丘,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評(píng)論 6 392
  • 文/花漫 我一把揭開白布勾给。 她就那樣靜靜地躺著滩报,像睡著了一般。 火紅的嫁衣襯著肌膚如雪播急。 梳的紋絲不亂的頭發(fā)上脓钾,一...
    開封第一講書人閱讀 51,578評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音桩警,去河邊找鬼可训。 笑死,一個(gè)胖子當(dāng)著我的面吹牛捶枢,可吹牛的內(nèi)容都是我干的握截。 我是一名探鬼主播,決...
    沈念sama閱讀 40,320評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼烂叔,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼谨胞!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蒜鸡,我...
    開封第一講書人閱讀 39,241評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤胯努,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后术瓮,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體康聂,經(jīng)...
    沈念sama閱讀 45,686評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評(píng)論 3 336
  • 正文 我和宋清朗相戀三年胞四,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了恬汁。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,992評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡辜伟,死狀恐怖氓侧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情导狡,我是刑警寧澤约巷,帶...
    沈念sama閱讀 35,715評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站旱捧,受9級(jí)特大地震影響独郎,放射性物質(zhì)發(fā)生泄漏踩麦。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評(píng)論 3 330
  • 文/蒙蒙 一氓癌、第九天 我趴在偏房一處隱蔽的房頂上張望谓谦。 院中可真熱鬧,春花似錦贪婉、人聲如沸反粥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽才顿。三九已至,卻和暖如春尤蒿,著一層夾襖步出監(jiān)牢的瞬間郑气,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評(píng)論 1 270
  • 我被黑心中介騙來泰國打工腰池, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留竣贪,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,173評(píng)論 3 370
  • 正文 我出身青樓巩螃,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親匕争。 傳聞我的和親對(duì)象是個(gè)殘疾皇子避乏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評(píng)論 2 355